C 中二进制除法的实现

问题描述 投票:0回答:1

这是实现二进制除法的代码:这是我在末尾打印最终数字的函数。

在 Windows 上我得到正确答案:

60000000 7948AECA D269AE4A 6B41DD10 64209812 293E346 1C0000

但在 Linux 上我只得到零。

#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 上工作,我必须改变什么?我应该不这样划分大的二进制数吗?

c linux division
1个回答
0
投票

存在多个问题:

  • 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 位。跟踪各个操作处理程序中的溢出将允许更紧凑的表示。

© www.soinside.com 2019 - 2024. All rights reserved.