/* * $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 #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 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 */