Here is the code which implements binary division: Here is the function where I print the final number at the end.
On Windows I get the correct answer: 60000000 7948AECA D269AE4A 6B41DD10 64209812 293E346 1C0000
but on Linux I get only zeroes.
#define SIZE_BIG_DECIMAL 7
typedef struct {
uint64_t bits[SIZE_BIG_DECIMAL];
uint16_t scale;
uint16_t sign;
} s21_big_decimal;
void binary_div(s21_big_decimal *value_1, s21_big_decimal value_2,
s21_big_decimal *result) {
init_s21_decimal(result);
s21_big_decimal Q;
s21_big_decimal R;
int scaleDiv = -1;
do {
init_s21_decimal(&R); // fill with 0 the array
init_s21_decimal(&Q);
scaleDiv++;
int lastBit = (SIZE_BIG_DECIMAL - 1) * 32 - 1;
int currentBit = get_bit_big(*value_1, lastBit);
while (currentBit == 0 && lastBit >= 0) {
currentBit = get_bit_big(*value_1, lastBit);
if (currentBit == 0)
lastBit--;
}
for (int i = lastBit; i >= 0; i--) {
change_left_big(&R, 1);
set_bit_big(&R, 0, get_bit_big(*value_1, i));
if (is_less_or_equal_big(value_2, R)) {
s21_big_decimal res = { 0 };
init_s21_decimal(&res);
s21_sub_big(R, value_2, &res);
init_s21_decimal(&R);
copy_bits(res, &R);
set_bit_big(&Q, i, 1);
}
}
if (scaleDiv > 0) {
mul_10_big(result);
}
s21_big_decimal res;
init_s21_decimal(&res);
add_big(*result, Q, &res);
copy_bits(res, result);
if (!is_zero_big(R)) {
init_s21_decimal(value_1);
mul_10_big(&R);
copy_bits(R, value_1);
}
} while (!is_zero_big(R) && scaleDiv < 28);
set_scale_big(result, scaleDiv);
for (int i = 0; i < 7; i++) {
printf("%lX ", result->bits[i]);
}
printf("\n");
}
I work with bits so here are some helper functions:
int mul_10_big(s21_big_decimal *dec)
{
s21_big_decimal temp = *dec;
for (int i = 0; i < SIZE_BIG_DECIMAL - 1; i++)
{
temp.bits[i] *= 10;
}
temp.scale++;
int overflowed = 0;
if (getoverflow(&temp))
{
overflowed = 1;
}
else
{
*dec = temp;
}
return overflowed;
}
int div_10_big(s21_big_decimal *dec)
{
uint64_t remained = 0;
for (int i = SIZE_BIG_DECIMAL - 2; i >= 0; i--)
{
dec->bits[i] += remained << 32;
remained = dec->bits[i] % 10;
dec->bits[i] /= 10;
}
dec->scale--;
return remained;
}
int getoverflow(s21_big_decimal *dec)
{
int overflow = 0;
int count = 0;
for (int i = 0; i < SIZE_BIG_DECIMAL - 1; i++)
{
dec->bits[i] += overflow;
overflow = (dec->bits[i] >> 32);
dec->bits[i] &= MAX4BITE;
count++;
}
int result = 0;
if (overflow != 0 && count == 6)
{
result = 1;
}
return result;
}
void set_scale_big(s21_big_decimal *big_dec, int scale_value)
{
big_dec->bits[SIZE_BIG_DECIMAL - 1] &= MINUS;
big_dec->bits[SIZE_BIG_DECIMAL - 1] |= (scale_value << 16) & SCALE;
}
The problem is not in the way I print, I guess the problem is in the size of the variable. it has to work on Linux, what I have to change? Should I divide large binary numbers not this way?
There are multiple problems:
The return type of
div_10_bigshould beuint64_tinstead ofintbut this does not pose a problem because the return value, the remainder of the division in in the range 0..9.It is unclear why you do not iterate on all elements in the loops in functions
div_10_big,getoverflow, andmul_10_big.It is unclear why
set_scale_bigmodifies the array instead of just thescalemember.The type
s21_big_decimalcan handle values much larger than the traditional one fors21_decimal, i.e.-79,228,162,514,264,337,593,543,950,335to79,228,162,514,264,337,593,543,950,335, with a scale from0to28, but usinguint64_tfor thebitsseems overkill as you only use 32 bits for each of thesebits. Tracking overflow in the individual operation handlers would allow for a more compact representation.The
printfin the output code actually has undefined behavior on Windows: inprintf("%lX ", result->bits[i]), you pass anunsigned long longwhereprintfexpects anunsigned long. For a portable version you should use: