整数在较高值处表现出奇怪的行为

时间:2016-01-18 04:50:20

标签: c# base-conversion

我在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,虽然超出了我的预感。

感谢您的帮助!

2 个答案:

答案 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)已经回答了,所以我只是让他解释为什么以及如何工作围绕它:)