BigInteger:在 C++ 中使用 ofstream 写入文件时将基数更改为 2 的方法?
BigInteger: Way to change base to 2 when writing to file using ofstream in C++?
我正在使用 C++ 中的 BigInteger 库来乘以一些大数并将它们写入文件。但是,我想在编写数字之前更改数字的基数。
我试过使用 std::setbase()
但它只会将其更改为基数 8、10 和 16。例如尝试 setbase(2)
会出错。
这是一个例子:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include "BigIntegerLibrary.hh"
#include "BigIntegerUtils.hh"
#include "BigIntegerAlgorithms.hh"
#include "BigUnsigned.hh"
#include "BigUnsignedInABase.hh"
#include "BigInteger.hh"
#include <stdio.h> /* printf, NULL */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
...
str1=randomStrGen(k);
str2=randomStrGen(j);
BigInteger s1 = stringToBigInteger(str1);
BigInteger s2 = stringToBigInteger(str2);
myfile<<str1<<" "<<str2<<" "<<"10"<<" "<<setbase(2)<<s1+s2<<" "<<s1*s2<<"\n";
...
给出错误:
terminate called after throwing an instance of 'char const*'
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
[Inferior 1 (process 5156) exited with code 03]
BigInteger 库下载自 https://mattmccutchen.net/bigint/,2010.04.30 发布。
问题是 std::setbase(2)
没有 切换到二进制表示,请参阅 here on cppreference:
Values of base other than 8, 10, or 16 reset basefield to zero, which corresponds to decimal output and prefix-dependent input.
这是一个自己的实现,用于获取将存储到 std::string
中的 BigUnsigned
的二进制表示,请注意,它假定您的机器将值存储在 little 中endian 表示。
函数 convertToBinary()
需要一个 BigUnsigned
因为这种类型可以执行更多的数学运算,例如获取位。这也意味着它只能用于 无符号数 .
此外,您应该考虑使用其他库,因为该库将不再维护(2010 年的最后一个版本),如 here:
所述
I have lost interest in maintaining this library and will not respond to most development or support inquiries.
完整代码:
#include "BigIntegerLibrary.hh"
#include <iostream>
#include <string>
std::string convertToBinary(const BigUnsigned& bigUns)
{
std::string binary;
for (size_t idx = 0; idx < bigUns.bitLength(); ++idx)
{
binary += (bigUns.getBit(bigUns.bitLength() - 1 - idx) ? "1" : "0");
}
return binary;
}
int main()
{
std::string str1 = "12";
std::string str2 = "18446744073709551615"; /* uint64 max */
BigInteger s1 = stringToBigInteger(str1);
BigInteger s2 = stringToBigInteger(str2);
s2 = s2 * 2;
std::cout << s1 << ": " << convertToBinary(s1.getMagnitude()) << std::endl;
std::cout << s2 << ": " << convertToBinary(s2.getMagnitude()) << std::endl;
return 0;
}
输出:
12: 1100
36893488147419103230: 11111111111111111111111111111111111111111111111111111111111111110
对于本机类型,您可以获得二进制表示,如评论中所述并已回答。
编辑#1:
由于 OP 在下面的评论中谈到了与任何基数的一般转换,这里是一个将 BigUnsigned
转换为返回 std::string
的任何基数的版本,函数名称是 convertToAnyBase()
。它的灵感来自 this snippet。但这只适用于无符号数,就像之前的解决方案一样。
要检查那些大数字转换,有一个很棒的在线工具,叫做 numberfacts。
完整代码(也包含上面的代码):
#include "BigIntegerLibrary.hh"
#include <iostream>
#include <string>
#include <vector>
std::string convertToBinary(const BigUnsigned& bigUns)
{
std::string binary;
for (size_t idx = 0; idx < bigUns.bitLength(); ++idx)
{
binary += (bigUns.getBit(bigUns.bitLength() - 1 - idx) ? "1" : "0");
}
return binary;
}
std::string convertToAnyBase(const BigUnsigned& bigUns_P, unsigned short base)
{
static const char baseDigits[16] =
{ '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
BigUnsigned bigUns = bigUns_P;
std::string anyBaseString;
std::vector<size_t> convertedNumber;
convertedNumber.reserve(bigUns.bitLength());
/* convert to the indicated base */
while (bigUns != 0)
{
convertedNumber.push_back((bigUns % base).toUnsignedInt());
bigUns = bigUns / base;
}
/* store result in reverse order */
for (std::vector<size_t>::const_reverse_iterator curNumber = convertedNumber.rbegin();
curNumber != convertedNumber.rend();
++curNumber)
{
anyBaseString += baseDigits[*curNumber];
}
return anyBaseString;
}
int main()
{
std::string str1 = "12";
std::string str2 = "18446744073709551615"; /* uint64 max */
BigInteger s1 = stringToBigInteger(str1);
BigInteger s2 = stringToBigInteger(str2);
s2 = s2 * 2;
std::cout << s1 << " binary: " << convertToBinary(s1.getMagnitude()) << "\n"
<< s2 << " binary: " << convertToBinary(s2.getMagnitude()) << "\n"
<< std::endl;
std::cout << s1 << " binary: " << convertToAnyBase(s1.getMagnitude(), 2) << "\n"
<< s2 << " binary: " << convertToAnyBase(s2.getMagnitude(), 2) << "\n"
<< std::endl;
std::cout << s1 << " octal: " << convertToAnyBase(s1.getMagnitude(), 8) << "\n"
<< s2 << " binary: " << convertToAnyBase(s2.getMagnitude(), 8) << "\n"
<< std::endl;
return 0;
}
输出:
12 binary: 1100
36893488147419103230 binary: 11111111111111111111111111111111111111111111111111111111111111110
12 binary (any base function): 1100
36893488147419103230 binary (any base function): 11111111111111111111111111111111111111111111111111111111111111110
12 octal (any base function): 14
36893488147419103230 octal (any base function): 3777777777777777777776
编辑#2:
转换为任何基数的更简单方法是使用 BigInteger 库提供的功能。它提供了 BigUnsignedInABase
class 支持转换为 std::string
,但这也只适用于 unsigned numbers:
std::string convertToAnyBase(const BigUnsigned& bigUns, unsigned short base)
{
BigUnsignedInABase bigBase(bigUns, base);
return static_cast<std::string> (bigBase);
}
如果您还想使用带符号的数字,则必须使用可用的 BigInteger 库中的 Two's complement. There is no operator !
(Two's complement) or operator ~
(One's complement),因此您必须在位上执行此操作并为您自己添加一个。
但这只适用于二进制(基数 2)转换。其他基础的问题是 BigInteger 库将 BigInteger
保存为符号 + BigUnsigned 作为聚合数,因此这里没有负数的任何其他二进制表示。
另一种可能是在字符串前面写上符号(BigInteger::getSign()
)并保留正数例如:
-12base{10} = -1100base{2} = -14base{8}
这是一个简单的代码更改,因为您只需传递 BigInteger
而不是 BigUnsigned
并使用适当的方法。
我正在使用 C++ 中的 BigInteger 库来乘以一些大数并将它们写入文件。但是,我想在编写数字之前更改数字的基数。
我试过使用 std::setbase()
但它只会将其更改为基数 8、10 和 16。例如尝试 setbase(2)
会出错。
这是一个例子:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include "BigIntegerLibrary.hh"
#include "BigIntegerUtils.hh"
#include "BigIntegerAlgorithms.hh"
#include "BigUnsigned.hh"
#include "BigUnsignedInABase.hh"
#include "BigInteger.hh"
#include <stdio.h> /* printf, NULL */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
...
str1=randomStrGen(k);
str2=randomStrGen(j);
BigInteger s1 = stringToBigInteger(str1);
BigInteger s2 = stringToBigInteger(str2);
myfile<<str1<<" "<<str2<<" "<<"10"<<" "<<setbase(2)<<s1+s2<<" "<<s1*s2<<"\n";
...
给出错误:
terminate called after throwing an instance of 'char const*'
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
[Inferior 1 (process 5156) exited with code 03]
BigInteger 库下载自 https://mattmccutchen.net/bigint/,2010.04.30 发布。
问题是 std::setbase(2)
没有 切换到二进制表示,请参阅 here on cppreference:
Values of base other than 8, 10, or 16 reset basefield to zero, which corresponds to decimal output and prefix-dependent input.
这是一个自己的实现,用于获取将存储到 std::string
中的 BigUnsigned
的二进制表示,请注意,它假定您的机器将值存储在 little 中endian 表示。
函数 convertToBinary()
需要一个 BigUnsigned
因为这种类型可以执行更多的数学运算,例如获取位。这也意味着它只能用于 无符号数 .
此外,您应该考虑使用其他库,因为该库将不再维护(2010 年的最后一个版本),如 here:
所述I have lost interest in maintaining this library and will not respond to most development or support inquiries.
完整代码:
#include "BigIntegerLibrary.hh"
#include <iostream>
#include <string>
std::string convertToBinary(const BigUnsigned& bigUns)
{
std::string binary;
for (size_t idx = 0; idx < bigUns.bitLength(); ++idx)
{
binary += (bigUns.getBit(bigUns.bitLength() - 1 - idx) ? "1" : "0");
}
return binary;
}
int main()
{
std::string str1 = "12";
std::string str2 = "18446744073709551615"; /* uint64 max */
BigInteger s1 = stringToBigInteger(str1);
BigInteger s2 = stringToBigInteger(str2);
s2 = s2 * 2;
std::cout << s1 << ": " << convertToBinary(s1.getMagnitude()) << std::endl;
std::cout << s2 << ": " << convertToBinary(s2.getMagnitude()) << std::endl;
return 0;
}
输出:
12: 1100
36893488147419103230: 11111111111111111111111111111111111111111111111111111111111111110
对于本机类型,您可以获得二进制表示,如评论中所述并已回答
编辑#1:
由于 OP 在下面的评论中谈到了与任何基数的一般转换,这里是一个将 BigUnsigned
转换为返回 std::string
的任何基数的版本,函数名称是 convertToAnyBase()
。它的灵感来自 this snippet。但这只适用于无符号数,就像之前的解决方案一样。
要检查那些大数字转换,有一个很棒的在线工具,叫做 numberfacts。
完整代码(也包含上面的代码):
#include "BigIntegerLibrary.hh"
#include <iostream>
#include <string>
#include <vector>
std::string convertToBinary(const BigUnsigned& bigUns)
{
std::string binary;
for (size_t idx = 0; idx < bigUns.bitLength(); ++idx)
{
binary += (bigUns.getBit(bigUns.bitLength() - 1 - idx) ? "1" : "0");
}
return binary;
}
std::string convertToAnyBase(const BigUnsigned& bigUns_P, unsigned short base)
{
static const char baseDigits[16] =
{ '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
BigUnsigned bigUns = bigUns_P;
std::string anyBaseString;
std::vector<size_t> convertedNumber;
convertedNumber.reserve(bigUns.bitLength());
/* convert to the indicated base */
while (bigUns != 0)
{
convertedNumber.push_back((bigUns % base).toUnsignedInt());
bigUns = bigUns / base;
}
/* store result in reverse order */
for (std::vector<size_t>::const_reverse_iterator curNumber = convertedNumber.rbegin();
curNumber != convertedNumber.rend();
++curNumber)
{
anyBaseString += baseDigits[*curNumber];
}
return anyBaseString;
}
int main()
{
std::string str1 = "12";
std::string str2 = "18446744073709551615"; /* uint64 max */
BigInteger s1 = stringToBigInteger(str1);
BigInteger s2 = stringToBigInteger(str2);
s2 = s2 * 2;
std::cout << s1 << " binary: " << convertToBinary(s1.getMagnitude()) << "\n"
<< s2 << " binary: " << convertToBinary(s2.getMagnitude()) << "\n"
<< std::endl;
std::cout << s1 << " binary: " << convertToAnyBase(s1.getMagnitude(), 2) << "\n"
<< s2 << " binary: " << convertToAnyBase(s2.getMagnitude(), 2) << "\n"
<< std::endl;
std::cout << s1 << " octal: " << convertToAnyBase(s1.getMagnitude(), 8) << "\n"
<< s2 << " binary: " << convertToAnyBase(s2.getMagnitude(), 8) << "\n"
<< std::endl;
return 0;
}
输出:
12 binary: 1100
36893488147419103230 binary: 11111111111111111111111111111111111111111111111111111111111111110
12 binary (any base function): 1100
36893488147419103230 binary (any base function): 11111111111111111111111111111111111111111111111111111111111111110
12 octal (any base function): 14
36893488147419103230 octal (any base function): 3777777777777777777776
编辑#2:
转换为任何基数的更简单方法是使用 BigInteger 库提供的功能。它提供了 BigUnsignedInABase
class 支持转换为 std::string
,但这也只适用于 unsigned numbers:
std::string convertToAnyBase(const BigUnsigned& bigUns, unsigned short base)
{
BigUnsignedInABase bigBase(bigUns, base);
return static_cast<std::string> (bigBase);
}
如果您还想使用带符号的数字,则必须使用可用的 BigInteger 库中的 Two's complement. There is no operator !
(Two's complement) or operator ~
(One's complement),因此您必须在位上执行此操作并为您自己添加一个。
但这只适用于二进制(基数 2)转换。其他基础的问题是 BigInteger 库将 BigInteger
保存为符号 + BigUnsigned 作为聚合数,因此这里没有负数的任何其他二进制表示。
另一种可能是在字符串前面写上符号(BigInteger::getSign()
)并保留正数例如:
-12base{10} = -1100base{2} = -14base{8}
这是一个简单的代码更改,因为您只需传递 BigInteger
而不是 BigUnsigned
并使用适当的方法。