将 10 基数转换为 .NET 中的任何基数的最快方法?
我有一个我写的旧(ish)C#方法,它接受一个数字并将其转换为任何基数:
string ConvertToBase(int number, char[] baseChars);
它并不是那么超级快速和简洁。 在 .NET 中是否有一种好的、已知的方法可以实现这一目标?
我正在寻找允许我使用 any 基和任意字符串的东西。
这只允许基数 16、10、8 和 2:
Convert.ToString(1, x);
我想用它来利用数字、所有小写和所有大写字母来实现极高的基数。 就像此线程中一样,但适用于 C# 而不是 JavaScript。
有谁知道在 C# 中执行此操作的良好且有效的方法吗?
I have and old(ish) C# method I wrote that takes a number and converts it to any base:
string ConvertToBase(int number, char[] baseChars);
It's not all that super speedy and neat. Is there a good, known way of achieving this in .NET?
I'm looking for something that allows me to use any base with an arbitrary string of characters to use.
This only allows bases 16, 10, 8 and 2:
Convert.ToString(1, x);
I want to use this to achieve a massively high base taking advantage of numbers, all lower case and all upper case letters. Like in this thread, but for C# not JavaScript.
Does anyone know of a good and efficient way of doing this in C#?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
可以使用
Convert.ToString
进行转换一个数字到其在指定基数中的等效字符串表示形式。示例:
但是,正如注释所指出的,
Convert.ToString
仅支持以下有限但通常足够的基数集:2、8、10 或 16。更新(以满足要求转换为任何基数):
我不知道 BCL 中是否有任何方法能够将数字转换为任何基数,因此您必须编写自己的小实用函数。 一个简单的示例如下所示(请注意,通过替换字符串连接肯定可以使速度更快):
更新 2(性能改进)
使用数组缓冲区而不是字符串连接来构建结果字符串可以提高性能,尤其是在处理大量数据时(参见方法
IntToStringFast
)。 在最好的情况下(即最长的可能输入),该方法大约快三倍。 但是,对于 1 位数字(即目标基数中的 1 位数字),IntToString
会更快。Convert.ToString
can be used to convert a number to its equivalent string representation in a specified base.Example:
However, as pointed out by the comments,
Convert.ToString
only supports the following limited - but typically sufficient - set of bases: 2, 8, 10, or 16.Update (to meet the requirement to convert to any base):
I'm not aware of any method in the BCL which is capable to convert numbers to any base so you would have to write your own small utility function. A simple sample would look like that (note that this surely can be made faster by replacing the string concatenation):
Update 2 (Performance Improvement)
Using an array buffer instead of string concatenation to build the result string gives a performance improvement especially on large number (see method
IntToStringFast
). In the best case (i.e. the longest possible input) this method is roughly three times faster. However, for 1-digit numbers (i.e. 1-digit in the target base),IntToString
will be faster.我最近在博客上谈到了这一点< /a>. 我的实现在计算过程中不使用任何字符串操作,这使得它非常快。 支持转换为以 2 到 36 为基数的任何数字系统:
我还实现了一个快速反函数,以防有人也需要它:
任意到十进制数字系统< /a>.
I recently blogged about this. My implementation does not use any string operations during the calculations, which makes it very fast. Conversion to any numeral system with base from 2 to 36 is supported:
I've also implemented a fast inverse function in case anyone needs it too:
Arbitrary to Decimal Numeral System.
快速“FROM”和“TO”方法
我迟到了,但我复合了以前的答案并对其进行了改进。 我认为这两种方法比迄今为止发布的任何其他方法都要快。 我能够在单核机器上在 400 毫秒内将 1,000,000 个数字与基数 36 相互转换。
下面的示例适用于 base 62。 更改
BaseChars
数组以在任何其他基数之间进行转换。编辑 (2018-07-12)
已修复,以解决 @AdrianBotor 发现的将 46655 转换为基数 36 的极端情况(请参阅评论)。这是由计算数学的小浮点错误引起的.Log(46656, 36) 正好是 3,但 .NET 返回
3 + 4.44e-16
,这会导致输出缓冲区中出现额外字符。FAST "FROM" AND "TO" METHODS
I am late to the party, but I compounded previous answers and improved over them. I think these two methods are faster than any others posted so far. I was able to convert 1,000,000 numbers from and to base 36 in under 400ms in a single core machine.
Example below is for base 62. Change the
BaseChars
array to convert from and to any other base.EDIT (2018-07-12)
Fixed to address the corner case found by @AdrianBotor (see comments) converting 46655 to base 36. This is caused by a small floating-point error calculating
Math.Log(46656, 36)
which is exactly 3, but .NET returns3 + 4.44e-16
, which causes an extra character in the output buffer.还可以使用已接受版本的稍微修改版本,并根据需要调整基本字符串:
One can also use slightly modified version of the accepted one and adjust base characters string to it's needs:
参加这个聚会已经很晚了,但我最近为工作中的一个项目编写了以下帮助程序类。 它的设计目的是将短字符串转换为数字,然后再转换回来(一个简单的完美哈希函数),但是它还将执行任意基数之间的数字转换。
Base10ToString
方法实现回答了最初发布的问题。需要将
shouldSupportRoundTripping
标志传递给类构造函数,以防止在转换为基数 10 并再次转换回来的过程中丢失数字字符串中的前导数字(鉴于我的要求,这一点至关重要!)。 大多数时候,数字字符串中前导 0 的丢失可能不会成为问题。无论如何,这是代码:
也可以对其进行子类化以派生自定义数字转换器:
并且代码将像这样使用:
Very late to the party on this one, but I wrote the following helper class recently for a project at work. It was designed to convert short strings into numbers and back again (a simplistic perfect hash function), however it will also perform number conversion between arbitrary bases. The
Base10ToString
method implementation answers the question that was originally posted.The
shouldSupportRoundTripping
flag passed to the class constructor is needed to prevent the loss of leading digits from the number string during conversion to base-10 and back again (crucial, given my requirements!). Most of the time the loss of leading 0s from the number string probably won't be an issue.Anyway, here's the code:
This can also be subclassed to derive custom number converters:
And the code would be used like this:
此论坛帖子中的课程可以帮助您吗?
完全未经测试...让我知道它是否有效! (复制粘贴它,以防论坛帖子消失或其他什么情况......)
Could this class from this forum post help you?
Totally untested... let me know if it works! (Copy-pasted it in case the forum post goes away or something...)
这是一种相当简单的方法,但可能不是最快的。 它非常强大,因为它是可组合的。
将此与这个简单的扩展方法结合起来,现在可以获取任何基础:
它可以像这样使用:
输出是:
This is a fairly straightforward way to do this, but it may not be the fastest. It is quite powerful because it is composable.
Combine this with this simple extension method and any getting any base is now possible:
It can be used like this:
The output is:
我也在寻找一种将十进制数转换为 [2..36] 范围内的另一个基数的快速方法,因此我开发了以下代码。 它很容易理解,并使用 Stringbuilder 对象作为字符缓冲区的代理,我们可以逐个字符地索引该字符缓冲区。 与替代方案相比,该代码似乎非常快,并且比初始化字符数组中的单个字符快得多。
为了您自己的使用,您可能更喜欢:
1/ 返回一个空字符串而不是抛出异常。
2/删除基数检查以使方法运行得更快
3/ 用 32 个 '0 初始化 Stringbuilder 对象并删除 result.Remove( 0, i ); 行。 这将导致返回的字符串带有前导零并进一步提高速度。
4/ 使 Stringbuilder 对象成为类中的静态字段,因此无论调用 DecimalToBase 方法多少次,Stringbuilder 对象都只会初始化一次。 如果您执行此更改,上述 3 将不再起作用。
我希望有人觉得这有用:)
AtomicParadox
I too was looking for a fast way to convert decimal number to another base in the range of [2..36] so I developed the following code. Its simple to follow and uses a Stringbuilder object as a proxy for a character buffer that we can index character by character. The code appears to be very fast compared to alternatives and a lot faster than initialising individual characters in a character array.
For your own use you might prefer to:
1/ Return a blank string rather than throw an exception.
2/ remove the radix check to make the method run even faster
3/ Initialise the Stringbuilder object with 32 '0's and remove the the line result.Remove( 0, i );. This will cause the string to be returned with leading zeros and further increase the speed.
4/ Make the Stringbuilder object a static field within the class so no matter how many times the DecimalToBase method is called the Stringbuilder object is only initialised the once. If you do this change 3 above would no longer work.
I hope someone finds this useful :)
AtomicParadox
这是基于帕维尔的答案,但消除了他不必要的负数字符串连接。 此外,基数是由传入的字符定义的,因此如果您想使用字符 ABC 将数字转换为基数 3,请传递“ABC” - 字符串长度 3 就是基数:
C#
VB.NET
This was based on Pavel's answer, but does away with his unnecessary string concat for negative numbers. Also the radix is defined by the chars passed in, so if you want to convert a number into base 3 using the chars ABC, pass "ABC" - the string length of 3 is the radix:
C#
VB.NET
我使用它来将 Guid 存储为较短的字符串(但仅限于使用 106 个字符)。
如果有人感兴趣,这里是我将字符串解码回数值的代码(在本例中,我使用 2 个 ulong 作为 Guid 值,而不是编码 Int128(因为我使用的是 3.5 而不是 4.0)。
为了清楚起见,CODE 是一个具有 106 个唯一字符的字符串常量。 ConvertLongsToBytes 相当乏味。
I was using this to store a Guid as a shorter string (but was limited to use 106 characters).
If anyone is interested here is my code for decoding the string back to numeric value (in this case I used 2 ulongs for the Guid value, rather than coding an Int128 (since I'm in 3.5 not 4.0).
For clarity CODE is a string const with 106 unique chars. ConvertLongsToBytes is pretty unexciting.
我有类似的需求,只是我也需要对“数字”进行数学计算。 我在这里采纳了一些建议,并创建了一个类来完成所有这些有趣的事情。 它允许使用任何 unicode 字符来表示数字,并且也适用于小数。
这个类非常容易使用。 只需创建一个数字作为
New BaseNumber
类型,设置一些属性,然后就可以了。 例程会自动在基数 10 和基数 x 之间切换,并且您设置的值将保留在您设置的基数中,因此不会丢失任何精度(直到转换为止,但即使如此,精度损失也应该非常小,因为这例程尽可能使用Double
和Long
)。我无法控制这个程序的速度。 它可能很慢,所以我不确定它是否适合提出问题的人的需求,但它肯定是灵活的,所以希望其他人可以使用它。
对于可能需要此代码来计算 Excel 中的下一列的其他人,我将包括我使用的利用此类的循环代码。
现在让代码循环遍历 Excel 列:
您会注意到 Excel 部分的重要部分是 0 在重新基数中由 @ 标识。 所以我只是过滤掉所有带有 @ 的数字,然后得到正确的序列(A、B、C、...、Z、AA、AB、AC、...)。
I had a similar need, except I needed to do math on the "numbers" as well. I took some of the suggestions here and created a class that will do all this fun stuff. It allows for any unicode character to be used to represent a number and it works with decimals too.
This class is pretty easy to use. Just create a number as a type of
New BaseNumber
, set a few properties, and your off. The routines take care of switching between base 10 and base x automatically and the value you set is preserved in the base you set it in, so no accuracy is lost (until conversion that is, but even then precision loss should be very minimal since this routine usesDouble
andLong
where ever possible).I can't command on the speed of this routine. It is probably quite slow, so I'm not sure if it will suit the needs of the one who asked the question, but it certain is flexible, so hopefully someone else can use this.
For anyone else that may need this code for calculating the next column in Excel, I will include the looping code I used that leverages this class.
And now for the code to loop through Excel columns:
You'll note the important part of the Excel part is that 0 is identified by a @ in the re-based number. So I just filter out all the numbers that have an @ in them and I get the proper sequence (A, B, C, ..., Z, AA, AB, AC, ...).