我正在开发一个"简单"的基数转换器,将基数为10的ULong转换为任意基数的字符串.这里我使用64个字符.用例是缩短存储为字符串的ULong.

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位以下的数字,但当数字的位数更多时,它开始变为round位.

17位导致8跳,18位导致32跳,19位导致256跳.

例如,42347959784570944左右的这些数字不起作用,结果是blocks:

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个进行了一些测试,但我就是找不到问题所在.

推荐答案

The exponent operator, ^, always returns a Double.
This means the entire expression (base ^ nPos) * Convert.ToUInt64(cPos) is evaluated and returned as Double (and then silently crammed into a ULong).

这带来了你正在观察的Double imprecision个.

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

假设您知道(base ^ nPos)不会超过最大值ULong(这似乎是假设),则修复为

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

.net相关问答推荐

是否必须使用 Visual Studio 预览才能使用 MAUI?

C#/.NET + VisualStudio,命名空间问题

使用 SSH.NET 查找具有特定文件名的最新 SFTP 文件

将 Span 传递到函数时出现 F# 错误

设置日志(log)文件名以在 Log4j 中包含当前日期

是什么让 Enum.HasFlag 这么慢?

如何明智地使用 StringBuilder?

在 Moq Callback() 调用中设置变量值

将 Topshelf 应用程序安装为 Windows 服务

如何判断一个类型是否是简单类型?即持有一个单一的价值

如何找到 ManualResetEvent 的状态?

数据库架构更改后更新 LINQ to SQL 类的最佳方法

C# 属性实际上是方法吗?

基于多个字符分隔符拆分字符串

Dapper 是否支持 SQL 2008 表值参数?

如何在 WPF 中的 Xaml 文件中添加注释?

List 是否保证项目将按照添加的顺序返回?

实体框架中的 POCO 是什么?

.NET 高级别的 .NET 4.0 和 .NET 4.5 的区别

枚举和匹配属性的 C# 命名约定