gpt4 book ai didi

.net - 为什么 ULong > 16 位的数学会变得不稳定?

转载 作者:行者123 更新时间:2023-12-02 18:08:22 26 4
gpt4 key购买 nike

我正在开发一个“简单”的基数转换器,将基数为 10 的 ULong 转换为任何基数的 String。这里我使用 64 个字符。 Usecase 是缩短 ULong,无论如何都存储为 String。

Public Class BaseConverter
'base64, but any length would work
Private Shared ReadOnly Characters() As Char = {"0"c, "1"c, "2"c, "3"c, "4"c, "5"c, "6"c, "7"c, "8"c, "9"c,
"a"c, "b"c, "c"c, "d"c, "e"c, "f"c, "g"c, "h"c, "i"c, "j"c, "k"c, "l"c, "m"c, "n"c, "o"c, "p"c, "q"c, "r"c, "s"c, "t"c, "u"c, "v"c, "w"c, "x"c, "y"c, "z"c,
"A"c, "B"c, "C"c, "D"c, "E"c, "F"c, "G"c, "H"c, "I"c, "J"c, "K"c, "L"c, "M"c, "N"c, "O"c, "P"c, "Q"c, "R"c, "S"c, "T"c, "U"c, "V"c, "W"c, "X"c, "Y"c, "Z"c,
"+"c, "-"c}

Public Shared Function Encode(number As ULong) As String
Dim buffer = New Text.StringBuilder()
Dim quotient = number
Dim remainder As ULong
Dim base = Convert.ToUInt64(Characters.LongLength)

Do
remainder = quotient Mod base
quotient = quotient \ base
buffer.Insert(0, Characters(remainder).ToString())
Loop While quotient <> 0

Return buffer.ToString()
End Function

Public Shared Function Decode(str As String) As ULong
If String.IsNullOrWhiteSpace(str) Then Return 0

Dim result As ULong = 0
Dim base = Convert.ToUInt64(Characters.LongLength)
Dim nPos As ULong = 0

For i As Integer = str.Length - 1 To 0 Step - 1
Dim cPos As Integer = Array.IndexOf(Of Char)(Characters, str(i))
result += (base ^ nPos) * Convert.ToUInt64(cPos)
nPos += 1
Next
Return result
End Function
End Class

它适用于最多 16 位的数字,但当数字有更多位时,它开始四舍五入很奇怪。

17 位数字导致 8 位跳跃,18 位数字导致 32 位跳跃,19 位数字导致 256 位跳跃。

例如,42347959784570944 附近的这些数字不起作用并导致那些 block :

42347959784570939 > 2msPWXX00X > 42347959784570936 ERROR
42347959784570940 > 2msPWXX00Y > 42347959784570944 ERROR
42347959784570941 > 2msPWXX00Z > 42347959784570944 ERROR
42347959784570942 > 2msPWXX00+ > 42347959784570944 ERROR
42347959784570943 > 2msPWXX00- > 42347959784570944 ERROR
42347959784570944 > 2msPWXX010 > 42347959784570944
42347959784570945 > 2msPWXX011 > 42347959784570944 ERROR
42347959784570946 > 2msPWXX012 > 42347959784570944 ERROR
42347959784570947 > 2msPWXX013 > 42347959784570944 ERROR
42347959784570948 > 2msPWXX014 > 42347959784570944 ERROR
42347959784570949 > 2msPWXX015 > 42347959784570952 ERROR

问题必须出在 Decode() 函数中,因为生成的字符串不同。

我对 https://dotnetfiddle.net/7wAGLh 进行了一些测试,但我就是找不到问题所在。

最佳答案

指数运算符,^always returns a Double .
means整个表达式 (base ^ nPos) * Convert.ToUInt64(cPos) 被评估并作为 Double 返回(然后默默地塞进 ULong ).

这带来了 Double imprecision你正在观察。

使用 Option Strict On始终是捕获这些错误的好方法。

前提是你知道(base ^ nPos)不会超过ULong的最大值(无论如何这似乎是假设),修复是

result += CULng(base ^ nPos) * Convert.ToUInt64(cPos)

关于.net - 为什么 ULong > 16 位的数学会变得不稳定?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72862641/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com