整数在较高值下表现出奇怪的行为
本文关键字:高值下 整数 | 更新日期: 2023-09-27 18:30:50
我在 C# 中创建了一个程序,用于将一个数字从一个基数转换为任何其他基数(例如,Base-10 中的 10 = Base-11 中的 A)。
对于每个目标基数,似乎存在程序导致不准确值的某个点。 例如,当从 Base-10 转换为 Base-11 然后转换回 Base-10 时,错误计算(导致比我开始的少一个整数)发生在等于或大于 45949729863572161 的值处(巧合地相当于 11 16;谁会想到?)。
为了进行转换,我首先将一个数字转换为 Base-10,然后转换为目标基数。我没有真正的猜测是导致此错误的原因
最有可能的罪魁祸首是主要方法。
A) 转换为基数 10 的方法
static string toBase10(string origVal, uint origBase)
{
ulong result = 0;
//Convert each character to base-ten so that base-ten arithmetic can be used
ulong[] b10Array = charsToBase10Readable(origVal, findSubArray(origBase));
//Run through each place value to convert entire number to base-ten
for (uint n = 0; n < b10Array.Length; n++)
{
ulong val = b10Array[n];
result += val * ((ulong)Math.Pow(origBase, b10Array.Length - n - 1));
}
return result.ToString();
}
}
B) 从 Base-10 转换的方法
static string fromBase10(ulong num, uint targetBase)
{
string result = string.Empty;
//Generate the original base
char[] targetBaseChars = findSubArray(targetBase);
do
{
result = targetBaseChars[num % (ulong)targetBase] + result;
num /= (ulong)targetBase;
}
while (num > 0);
return result;
}
其他潜在方法
static char[] findSubArray(uint i)
{
char[] subArray = new char[i];
for (uint n = 0; n < i; n++)
{
subArray[n] = masterBase[n];
}
return subArray;
}
如果上述方法不是问题,我的转换代码的更广泛版本可以作为 Github Gist 使用。
关于问题是什么的任何想法?我怀疑它是否达到了乌龙的最大值,尽管除此之外我不确定。
感谢您的任何帮助!
Math.Pow 以双打进行算术运算。双精度只有大约 16 位十进制数字;当数字在 10 到 16 的量级上时,您将开始累积表示错误。你的是。
请改用BigInteger.Pow()
。它具有任意大的精度。
顺便说一句,你不是第一个发现将 11 的 16 次方放入双精度的事实的人:
https://math.stackexchange.com/questions/91583/implementing-fermats-primality-test/91584#91584
我尝试使用将45949729863572161从基数 10 转换为基数 11 的测试用例在 LINQPad (v4) 中运行您的代码,我得到了正确答案 (10000000000000000000),我使用 Wolfram Alpha 进行了验证。
我还尝试进行相同的转换,将一个添加到您的值中(即 45949729863572162),但我仍然得到了正确的答案 (10000000000000001)。
所以,我认为你的问题的答案是,要么行为不像你想象的那么奇怪,要么你使用的是有错误的旧版本的编译器。
回复您的评论,问题似乎与Math.Pow
功能有关。
Math.Pow(11, 16)
正在产生45949729863572160而不是45949729863572161。当我输入这个时,我看到主人(Eric Lippert)已经回答了,所以我就让他解释为什么以及如何解决这个问题:)