You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言二进制除法实现:Windows正常Linux输出全零问题排查

跨平台大二进制数除法的Windows/Linux差异问题

我实现了一个大二进制数除法的代码,在Windows下能输出正确结果:60000000 7948AECA D269AE4A 6B41DD10 64209812 293E346 1C0000,但在Linux下输出全为0。已经排除了打印方式的问题,怀疑是变量大小导致的跨平台差异,请问要修改哪里?是否需要更换除法实现方式?

核心除法实现代码

#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;
}

问题定位与修改方案

1. 核心位索引错误(最关键)

代码中bits数组是uint64_t类型,但位索引计算按32位元素处理:

int lastBit = (SIZE_BIG_DECIMAL - 1) * 32 - 1;

这会导致程序一开始找不到有效最高位,后续循环完全不执行,最终结果全为0。修改为:

int lastBit = (SIZE_BIG_DECIMAL - 1) * 64 - 1;

同时,get_bit_big、set_bit_big、change_left_big等位操作函数,必须全部适配64位元素:计算位所属数组下标用n / 64,位偏移用n % 64,而不是32。

2. mul_10_big进位逻辑错误

当前实现先直接对所有元素乘10再处理溢出,会导致64位元素溢出后丢失高位数据。正确的大整数乘10应该从低位到高位逐位处理进位:

int mul_10_big(s21_big_decimal *dec)
{
  s21_big_decimal temp = *dec;
  uint64_t carry = 0;
  for (int i = 0; i < SIZE_BIG_DECIMAL - 1; i++)
  {
    uint64_t product = temp.bits[i] * 10 + carry;
    temp.bits[i] = product & 0xFFFFFFFF; // 保留低32位(和原有逻辑对齐)
    carry = product >> 32; // 提取进位
  }
  temp.scale++;
  int overflowed = (carry != 0) ? 1 : 0;
  if (!overflowed)
  {
    *dec = temp;
  }
  return overflowed;
}

3. 宏定义跨平台一致性检查

确保MAX4BITE、MINUS、SCALE的定义在Windows和Linux下一致:

  • MAX4BITE必须是0xFFFFFFFF(32位全1),用于保留低32位数据
  • MINUS必须是0x8000000000000000(64位最高位,符号位)
  • SCALE必须是0x00FF000000000000(对应scale的16位存储区域)

是否需要更换除法实现?

不需要更换核心长除法逻辑,上述修改即可解决跨平台差异问题。当前的长除法逻辑是正确的,问题仅出在细节的位索引、进位处理和宏定义上。


内容的提问来源于stack exchange,提问作者laptop22

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 02:57:05