How to convert a string into an arbitrary length integer
我正在一个项目中实现C语言中的多精度算法。我有点跌倒了。我正在尝试将c字符串转换为整数的二进制表示形式,该整数可能包含比int可以容纳的位数更多的位(理论上,这可以是任意数量的位)。我本质上想创建一个long数组,该数组将容纳字符串中包含的数字的二进制表示形式,索引0是该数字的最低有效"四肢"。我假设数字以10为底。
我已经研究过使用GMP中的代码,但是它对我的需求来说不必要地复杂,并且具有大量依赖于平台的代码。
任何帮助都会很棒!如果您需要更多详细信息,请告诉我。
就像@SteveJessop说的那样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 != '\\0' ) { *this *= 10; *this += *string - '0'; string++; } } |
您要做的第一件事就是拥有一个运行正常的测试引擎。这是一个脑筋急转弯,易于理解,任意精度的算术引擎。
此引擎的用途有几个方面。首先,它使将字符串转换为任意精度的整数变得非常容易。其次,这是测试您以后改进的引擎的一种方法。即使它真的很慢,您也会确信它是正确的(并且拥有两个独立的实现意味着即使其中一个都不那么有信心,另一个实现中也可能会遇到极端的错误)。 假定
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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来"改进"一个基本的任意精度库。目标是只编写