如何将字符串转换为任意长度的整数
How to convert a string into an arbitrary length integer
我正在做一个用C++实现多精度算术的项目。我在第一个栏上就摔倒了。我正试图将c字符串转换为整数的二进制表示,该整数可能包含比int所能容纳的比特更多的比特(理论上这可能是任意数量的比特)。我本质上想创建一个长数组,它将保存字符串中包含的数字的二进制表示,索引0是数字的最低有效"分支"。我假设这个数字是以10为基数的。
我已经研究过使用GMP中的代码,但它对我的需求来说是不必要的复杂,并且有大量依赖于平台的代码。
任何帮助都会很棒!如果你需要更多的细节,请告诉我。
就像@StevenJessop说的
class Number {
public:
Number();
void FromString( const char * );
void operator *= ( int );
void operator += ( int );
void operator = ( int );
}
Number::FromString( const char * string )
{
*this = 0;
while( *string != ' ' ) {
*this *= 10;
*this += *string - '0';
string++;
}
}
您想要做的第一件事就是拥有一个可工作的测试引擎。这是一个脑死亡,易于理解,任意精度的算术引擎。
这台发动机的用途有几个方面。首先,它使字符串转换为任意精度整数变得非常容易。其次,这是一种测试你后来改进的发动机的方法。即使它真的很慢,你也会更确信它是正确的(拥有两个独立的实现意味着一个实现中的角情况错误可能会被另一个捕获,即使你对其中任何一个都不更有信心)。
假设short
至少为16位,char
至少为8位(如果编译器支持,请使用实际的int_8
样式类型)
short Add(unsigned char left, unsigned char right, unsigned char extra=0) { return unsigned short(left)+unsigned short(right)+unsigned short(extra); }
unsigned short Multiply(unsigned char left, unsigned char right) { return unsigned short(left)*unsigned short(right); }
std::pair<unsigned char,unsigned char> CarryCalc(unsigned short input) {
std::pair<unsigned char,unsigned char> retval;
retval.first = input & (1<<8-1);
retval.second = input>>8;
return retval;
}
struct BigNum {
std::vector<char> base256;
BigNum& operator+=( BigNum const& right ) {
if (right.base256.size() > base256.size())
base256.resize(right.base256.size());
auto lhs = base256.begin();
auto rhs = right.base256.begin();
char carry = 0;
for(; rhs != right.base256.end(); ++rhs, ++lhs) {
auto result = CarryCalc( Add( *lhs, *rhs, carry ) );
*lhs = result.first;
carry = result.second;
}
while( carry && lhs != base256.end() ) {
auto result = CarryCalc( Add( *lhs, 0, carry ) );
*lhs = result.first;
carry = result.second;
}
if (carry)
base256.push_back(carry);
return *this;
}
BigNum& scaleByChar( unsigned char right ) {
char carry = 0;
for(auto lhs = base256.begin(); lhs != base256.end(); ++lhs) {
unsigned short product = Multiply( *lhs, right );
product += carry;
auto result = CarryCalc( product );
*lhs = result.first;
carry = result.second;
}
if (carry)
base256.push_back(carry);
return *this;
}
BigNum& shiftRightBy8BitsTimes( unsigned int x ) {
if (x > base256.size()) {
base256.clear();
return *this;
}
base256.erase( base256.begin(), base256.begin()+x) )
return *this;
}
// very slow, O(x * n) -- should be O(n) at worst
BigNum& shiftLeftBy8BitsTimes( unsigned int x ) {
while( x != 0 ) {
base256.insert( base256.begin(), 0 );
--x;
}
return *this;
}
// very slow, like O(n^3) or worse (should be O(n^2) at worst, fix shiftLeft)
BigNum& operator*=( BigNum const& right ) {
unsigned int digit = 0;
BigNum retval;
while (digit < right.base256.size()) {
BigNum tmp = *this;
tmp.shiftLeftBy8BitsTimes( digit );
tmp.scaleByChar( right.base256[digit] );
retval += tmp;
++digit;
}
*this = retval;
return *this;
}
};
这是一个快速而肮脏的任意精度整数类型(甚至还没有编译),具有糟糕的性能。测试上面的东西,说服自己它是坚固的,然后从那里开始建立。
您的大部分代码都可以将实际的BigNum类作为模板参数,因此您可以对两个不同的实现执行相同的算法,并将结果进行比较以进行测试。
哦,还有另一条建议——编写一个模板类,通过CRTP"改进"一个基本的任意精度库。目标是只需要编写*=
、+=
、unary -
,可能还有/=
和一些shift_helper
和compare_helper
函数,并让模板自动为您编写其余方法。通过将样板放在一个位置,可以更容易地维护BigNum
类的多个版本:并且拥有多个版本对于测试来说非常重要。
- 如何将argv字符串更改为大数字的长整数
- 涡轮增压C++结果无法与长整数
- 长整数的意外模仿行为
- 有符号长整数的含义
- 如何在 c++ 中解释对长整数的操作
- 垃圾价值通过,同时总结一系列长整数
- 长整数不适用于 8 的幂C++
- 从文件到短 /长整数读取字节
- C++长整数奇数
- 任意精度整数词汇中的肢体
- 给定一个n位数的长整数,如何访问其部分
- 将长整数转换为字符数组的最安全方法是什么
- 使用构造函数c++将一个长整数转换为类对象
- 将一个长字符串除以一个长整数
- 如何在C++中使用宏生成任意长的参数列表
- 无法从嵌入式Python返回长整数到c++
- 如何得到长整数的两个组成部分
- 如何将长整数和/或无符号整数传递给 MPI 参数
- C++ 获取从 0 到最大长整数的随机数
- 将长整数秒转换为双精度浮点值