我在C#中创建了一个程序,用于将数字从一个基数转换为任何其他基数(例如 Base-10中的10 = Base-11 中的A )。
对于每个目标基础,似乎某个程度导致程序导致不准确的值。例如,当从 Base-10 转换为 Base-11 然后返回 Base-10 时,计算错误(导致整数减少一个)比我开始的时候发生的任何值等于或大于 45949729863572161 (这恰好相当于11 16 ;谁会想到?)。
要进行转换,我首先将数字转换为 Base-10 ,然后转换为目标库。我没有真正猜测这个错误的原因是什么意义
最可能的罪魁祸首是主要方法。
A)将转换为 Base-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。
关于问题是什么的任何想法?我怀疑它是在击中ulong's max,虽然超出了我的预感。
感谢您的帮助!
答案 0 :(得分:7)
Math.Pow在双打中算术。双打只有大约16个十进制数字的精度;当数字大约为10到16时,你会开始得到表示错误。你的是哪个。
请改用BigInteger.Pow()
。它具有任意大的精度。
顺便说一句,你并不是第一个发现这个事实的人,即将第16个权力放入第16个权力中:
https://math.stackexchange.com/questions/91583/implementing-fermats-primality-test/91584#91584
答案 1 :(得分:2)
我尝试使用您将45949729863572161从基数10转换为基数11的测试用例在LINQPad(v4)中运行代码,我得到了正确答案(10000000000000000),我使用Wolfram Alpha进行了验证。
我也尝试使用添加到您的值的相同转换(即45949729863572162),我仍然得到了正确答案(10000000000000001)。
所以,我认为您的问题的答案是,行为不是您想象的那么奇怪,或者您使用的旧版本的编译器有错误。
回复您的评论时,问题似乎与Math.Pow
功能有关。
Math.Pow(11, 16)
正在产生45949729863572160而不是45949729863572161。正如我打字一样,我看到主人(Eric Lippert)已经回答了,所以我只是让他解释为什么以及如何工作围绕它:)