【问题标题】:How to effectively store large number in integer array? C++如何有效地将大数存储在整数数组中? C++
【发布时间】:2018-05-18 14:46:03
【问题描述】:

大家好!我有一个家庭作业,我需要构建一个可以处理非常大数字的高精度计算器。这个分配的重点是现在允许将数组中的值存储为一个数字到单独的数组单元格。

那是数字的记忆表示

335897294593872

像这样

int number[] = {3, 3, 5, 8, 9, 7, 2, 9, 4, 5, 9, 3, 8, 7, 2};

不合法,

也没有

char number[] = {3, 3, 5, 8, 9, 7, 2, 9, 4, 5, 9, 3, 8, 7, 2};

也没有

std::string number("335897294593872");

我想要做的是将整数分成 32 位块,并将每个单独的块存储在单独的数组单元格数据类型中,数据类型为 u32int_t。

由于我从键盘获得输入,我最初将所有值存储在 std::string 中,然后将它们放入整数数组中以执行操作。

如何将大数的二进制表示放入整数数组中正确填充所有位?

提前谢谢你。

编辑:仅使用标准 C++ 库

EDIT2:我希望能够对具有大数字的数组进行加、减、乘、除,所以我的意思不仅仅是将字符串切分并将十进制表示形式存储在整数数组中,而是保留数字本身的位顺序能够计算进位。

【问题讨论】:

标签: c++ arrays string integer


【解决方案1】:

这是一个相当幼稚的解决方案:

  1. 如果字符串中的最后一位为奇数,则在结果中存储 1(否则保留 0)。
  2. 将字符串中的数字除以 2(考虑进位)。
  3. 如果已写入 32 位,则向结果向量添加另一个元素。
  4. 重复此操作,直到字符串仅包含 0。

源代码:

#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

std::vector<uint32_t> toBigInt(std::string text)
{
  // convert string to BCD-like
  for (char &c : text) c -= '0';
  // build result vector
  std::vector<uint32_t> value(1, 0);
  uint32_t bit = 1;
  for (;;) {
    // set next bit if last digit is odd
    if (text.back() & 1) value.back() |= bit;
    // divide BCD-like by 2
    bool notNull = false; int carry = 0;
    for (char &c : text) {
      const int carryNew = c & 1;
      c /= 2; c += carry * 5;
      carry = carryNew;
      notNull |= c;
    }
    if (!notNull) break;
    // shift bit
    bit <<= 1;
    if (!bit) {
      value.push_back(0); bit = 1;
    }
  }
  // done
  return value;
}

std::ostream& operator<<(std::ostream &out, const std::vector<uint32_t> &value)
{
  std::ios fmtOld(0); fmtOld.copyfmt(out);
  for (size_t i = value.size(); i--;) {
    out << std::hex << value[i] << std::setfill('0') << std::setw(sizeof (uint32_t) * 2);
  }
  out.copyfmt(fmtOld);
  return out;
}

int main()
{
  std::string tests[] = {
    "0", "1",
    "4294967295", // 0xffffffff
    "4294967296", // 0x100000000
    "18446744073709551615", // 0xffffffffffffff
    "18446744073709551616", // 0x100000000000000
  };
  for (const std::string &test : tests) {
    std::cout << test << ": " << toBigInt(test) << '\n';
  }
  return 0;
}

输出:

0: 0
1: 1
4294967295: ffffffff
4294967296: 100000000
18446744073709551615: ffffffffffffffff
18446744073709551616: 10000000000000000

Live Demo on coliru

注意事项:

  1. 输出为小端。 (最不重要的元素排在第一位。)
  2. 对于tests,我使用了十六进制代码易于肉眼检查的数字。

【讨论】:

  • 非常感谢!这很有帮助。
【解决方案2】:

使用数组来存储大数的不同部分是完成这项工作的常用方法。要考虑的另一件事是考虑signed ints 的不同架构实现,这导致你不得不牺牲(这是处理大整数的普通库所做的)以允许signedunsigned 转换(你在这里有几种方法)在你的数字的各个部分之间或者你将如何实现不同的算术运算。

我一般不建议对数组单元使用 long long 整数版本,因为它们通常不是架构的原生大小,所以为了给架构一些机会来有效地做事,我应该使用缩减的(至少一位,能够看到从一个扩展数字到下一个的执行)标准unsigned(例如,gnu **libgmp* 使用每个数组单元格上的 24 位整数 --- 上次我检查过)。将其减小到 char 大小的倍数也很常见,因此数字的位移和重新分配比在完整的位数组上进行 31 bit 位移更容易。

【讨论】:

    【解决方案3】:

    当你处理金钱或微妙的数字时,你经常使用整数是很常见的,因为你可以保证很多事情,所以我的建议是,每当你处理这个大数字时,模拟一个固定点或浮点数——具有两个 Int 的点算术,因此您可以“观察”一切是如何执行的,您可以检查 IEEE 754 浮点标准。 如果您将数字存储在数组中,请确保采取恒定数量的步骤来完成您在操作时所做的所有操作。这可能很棘手。

    我建议您相信整数,但要固定位的大小。 但是,如果你真的想寻找有趣的东西,试着使用按位运算符,也许你可以得到一些有趣的东西。

    您可以查看here 数据类型的详细信息,特别是signed short intlong long int,并确认数据类型的大小请查看this

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-17
      • 2014-02-18
      • 1970-01-01
      • 2014-03-03
      • 2019-06-12
      • 1970-01-01
      • 2018-07-18
      相关资源
      最近更新 更多