You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
5.9 KiB
256 lines
5.9 KiB
/*
|
|
* $Id: bcd2.c,v 1.2 2005/01/03 20:08:58 jms Exp $
|
|
*
|
|
* Revision History
|
|
* ===================
|
|
* $Log: bcd2.c,v $
|
|
* Revision 1.2 2005/01/03 20:08:58 jms
|
|
* change line terminations
|
|
*
|
|
* Revision 1.1.1.1 2004/11/24 23:31:45 jms
|
|
* re-establish external server
|
|
*
|
|
* Revision 1.1.1.1 2003/04/03 18:54:21 jms
|
|
* recreation after CVS crash
|
|
*
|
|
* Revision 1.1.1.1 2003/04/03 18:54:21 jms
|
|
* initial checkin
|
|
*
|
|
*
|
|
*/
|
|
/*
|
|
* bcd.c: conversion routines for multi-byte arithmetic
|
|
*
|
|
* defined routines:
|
|
* bin_bcd2(long binary, long *low_res, long *high_res)
|
|
* bcd2_bin(long *dest, long bcd)
|
|
* bcd2_add(long *bcd_low, long *bcd_high, long addend)
|
|
* bcd2_sub(long *bcd_low, long *bcd_high, long subend)
|
|
* bcd2_mul(long *bcd_low, long *bcd_high, long multiplier)
|
|
* bcd2_div(long *bcd_low, long *bcd_high, long divisor)
|
|
* long bcd2_mod(long *bcd_low, long *bcd_high, long modulo)
|
|
* long bcd2_cmp(long *bcd_low, long *bcd_high, long compare)
|
|
*/
|
|
#include <stdio.h>
|
|
#include "bcd2.h" /* for function prototypes */
|
|
|
|
#define DIGITS_PER_LONG 7
|
|
#define WORD_DIVISOR 10000000
|
|
#define GET_DIGIT(num, low, high) \
|
|
((num) >= DIGITS_PER_LONG)? \
|
|
(high & (0xF << (4 * ((num) - DIGITS_PER_LONG)))) \
|
|
>> (((num) - DIGITS_PER_LONG) * 4): \
|
|
(low & (0xF << (4 * (num)))) >> ((num) * 4)
|
|
#define SET_DIGIT(value, num, low, high) \
|
|
if ((num) >= DIGITS_PER_LONG) \
|
|
{ \
|
|
*high &= \
|
|
(0xFFFFFFF ^ (0xF << (4 * ((num) - DIGITS_PER_LONG)))); \
|
|
*high |= (value << (4 * ((num) - DIGITS_PER_LONG))); \
|
|
} \
|
|
else \
|
|
{ \
|
|
*low = (*low & (0xFFFFFFF ^ (0xF << (4 * (num))))); \
|
|
*low |= (value << (4 * (num))); \
|
|
}
|
|
int
|
|
bin_bcd2(long binary, long *low_res, long *high_res)
|
|
{
|
|
char number[15],
|
|
*current;
|
|
int count;
|
|
long *dest;
|
|
|
|
*low_res = *high_res = 0;
|
|
sprintf(number, "%014ld", binary);
|
|
for (current = number, count=13; *current; current++, count--)
|
|
{
|
|
dest = (count < DIGITS_PER_LONG)?low_res:high_res;
|
|
*dest = *dest << 4;
|
|
*dest |= *current - '0';
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
bcd2_bin(long *dest, long bcd)
|
|
{
|
|
int count;
|
|
long mask;
|
|
|
|
count = DIGITS_PER_LONG - 1;
|
|
mask = 0xF000000;
|
|
*dest = 0;
|
|
while (mask)
|
|
{
|
|
*dest *= 10;
|
|
*dest += (bcd & mask) >> (4 * count);
|
|
mask = mask >> 4;
|
|
count -= 1;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
bcd2_add(long *bcd_low, long *bcd_high, long addend)
|
|
{
|
|
long tmp_lo, tmp_hi, carry, res;
|
|
int digit;
|
|
|
|
bin_bcd2(addend, &tmp_lo, &tmp_hi);
|
|
carry = 0;
|
|
for (digit=0; digit < 14; digit++)
|
|
{
|
|
res = GET_DIGIT(digit, *bcd_low, *bcd_high);
|
|
res += GET_DIGIT(digit, tmp_lo, tmp_hi);
|
|
res += carry;
|
|
carry = res / 10;
|
|
res %= 10;
|
|
SET_DIGIT(res, digit, bcd_low, bcd_high);
|
|
}
|
|
return(carry);
|
|
}
|
|
|
|
int
|
|
bcd2_sub(long *bcd_low, long *bcd_high, long subend)
|
|
{
|
|
long tmp_lo, tmp_hi, carry, res;
|
|
int digit;
|
|
|
|
bin_bcd2(subend, &tmp_lo, &tmp_hi);
|
|
carry = 0;
|
|
for (digit=0; digit < 14; digit++)
|
|
{
|
|
res = GET_DIGIT(digit, *bcd_low, *bcd_high);
|
|
res -= GET_DIGIT(digit, tmp_lo, tmp_hi);
|
|
res -= carry;
|
|
if (res < 0)
|
|
{
|
|
res += 10;
|
|
carry = 1;
|
|
}
|
|
SET_DIGIT(res, digit, bcd_low, bcd_high);
|
|
}
|
|
return(carry);
|
|
}
|
|
|
|
int
|
|
bcd2_mul(long *bcd_low, long *bcd_high, long multiplier)
|
|
{
|
|
long tmp_lo, tmp_hi, carry, m_lo, m_hi, m1, m2;
|
|
int udigit, ldigit, res;
|
|
|
|
tmp_lo = *bcd_low;
|
|
tmp_hi = *bcd_high;
|
|
bin_bcd2(multiplier, &m_lo, &m_hi);
|
|
*bcd_low = 0;
|
|
*bcd_high = 0;
|
|
carry = 0;
|
|
for (ldigit=0; ldigit < 14; ldigit++)
|
|
{
|
|
m1 = GET_DIGIT(ldigit, m_lo, m_hi);
|
|
carry = 0;
|
|
for (udigit=0; udigit < 14; udigit++)
|
|
{
|
|
m2 = GET_DIGIT(udigit, tmp_lo, tmp_hi);
|
|
res = m1 * m2;
|
|
res += carry;
|
|
if (udigit + ldigit < 14)
|
|
{
|
|
carry = GET_DIGIT(udigit + ldigit, *bcd_low, *bcd_high);
|
|
res += carry;
|
|
}
|
|
carry = res / 10;
|
|
res %= 10;
|
|
if (udigit + ldigit < 14)
|
|
SET_DIGIT(res, udigit + ldigit, bcd_low, bcd_high);
|
|
}
|
|
}
|
|
return(carry);
|
|
}
|
|
|
|
int
|
|
bcd2_div(long *bcd_low, long *bcd_high, long divisor)
|
|
{
|
|
long tmp_lo, tmp_hi, carry, d1, res, digit;
|
|
|
|
|
|
carry = 0;
|
|
tmp_lo = *bcd_low;
|
|
tmp_hi = *bcd_high;
|
|
*bcd_low = *bcd_high = 0;
|
|
for (digit=13; digit >= 0; digit--)
|
|
{
|
|
d1 = GET_DIGIT(digit, tmp_lo, tmp_hi);
|
|
d1 += 10 * carry;
|
|
res = d1 / divisor;
|
|
carry = d1 % divisor;
|
|
SET_DIGIT(res, digit, bcd_low, bcd_high);
|
|
}
|
|
return(carry);
|
|
}
|
|
|
|
long
|
|
bcd2_mod(long *bcd_low, long *bcd_high, long modulo)
|
|
{
|
|
long tmp_low, tmp_high;
|
|
|
|
tmp_low = *bcd_low;
|
|
tmp_high = *bcd_high;
|
|
while (tmp_high || tmp_low > modulo)
|
|
bcd2_sub(&tmp_low, &tmp_high, modulo);
|
|
return(tmp_low);
|
|
}
|
|
|
|
long
|
|
bcd2_cmp(long *low1, long *high1, long comp)
|
|
{
|
|
long temp = 0;
|
|
|
|
bcd2_bin(&temp, *high1);
|
|
if (temp > 214)
|
|
return(1);
|
|
bcd2_bin(&temp, *low1);
|
|
return(temp - comp);
|
|
}
|
|
|
|
#ifdef TEST_BCD
|
|
#include <values.h>
|
|
|
|
main()
|
|
{
|
|
long bin, low_bcd, high_bcd;
|
|
int i;
|
|
|
|
bin = MAXINT;
|
|
printf("%ld\n", bin);
|
|
bin_bcd2(bin, &low_bcd, &high_bcd);
|
|
printf("%ld %ld\n", high_bcd, low_bcd);
|
|
bin = 0;
|
|
bcd2_bin(&bin, high_bcd);
|
|
bcd2_bin(&bin, low_bcd);
|
|
printf( "%ld\n", bin);
|
|
for (i=9; i >= 0; i--)
|
|
printf("%dth digit in %d is %d\n",
|
|
i, bin, GET_DIGIT(i, low_bcd, high_bcd));
|
|
bcd2_add(&low_bcd, &high_bcd, MAXINT);
|
|
bin = 0;
|
|
bcd2_bin(&bin, high_bcd);
|
|
high_bcd = bin;
|
|
bin = 0;
|
|
bcd2_bin(&bin, low_bcd);
|
|
low_bcd = bin;
|
|
printf( "%ld%07ld\n", high_bcd, low_bcd);
|
|
bin_bcd2(14, &low_bcd, &high_bcd);
|
|
bcd2_mul(&low_bcd, &high_bcd, 23L);
|
|
bin = 0;
|
|
bcd2_bin(&bin, high_bcd);
|
|
bcd2_bin(&bin, low_bcd);
|
|
printf( "%ld\n", bin);
|
|
bcd2_div(&low_bcd, &high_bcd, 10L);
|
|
bin = 0;
|
|
bcd2_bin(&bin, high_bcd);
|
|
bcd2_bin(&bin, low_bcd);
|
|
printf( "%ld\n", bin);
|
|
}
|
|
#endif /* TEST */
|
|
|