这是实现二进制除法的代码:这是我在末尾打印最终数字的函数。
在 Windows 上我得到正确答案:
60000000 7948AECA D269AE4A 6B41DD10 64209812 293E346 1C0000
#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");
}
我使用位,所以这里有一些辅助函数:
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;
}
问题不在于我的打印方式,我猜问题在于变量的大小。它必须在 Linux 上工作,我必须改变什么?我应该不这样划分大的二进制数吗?
存在多个问题:
div_10_big
的返回类型应该是uint64_t
而不是int
但这不会造成问题,因为返回值,除法的余数在0..9.范围内
尚不清楚为什么不在函数
div_10_big
、getoverflow
和 mul_10_big
中的循环中迭代所有元素。
尚不清楚为什么
set_scale_big
修改数组而不是仅修改 scale
成员。
类型
s21_big_decimal
可以处理比传统s21_decimal
大得多的值,即:-79,228,162,514,264,337,593,543,950,335
到79,228,162,514,264,337,593,543,950,335
,范围从0
到28
,但使用uint64_t
作为bits
似乎太过分了,因为每个 bits
只使用 32 位。跟踪各个操作处理程序中的溢出将允许更紧凑的表示。