英文:
Converting a BigNum (binary w/ repeating digits) to decimal
问题
我目前有一个基于有理数(带有重复数字)的大数实现,存储以下内容(以二进制表示):
- 整数部分
- 小数部分
- 重复小数部分
一些示例(表示为<int>.<frac>(<repeating-frac>)):
2.5(十进制):10.1(二进制)2.1(十进制):10.0(0011)(二进制)2.5(3)(十进制):10.(1000)(二进制)
我可以通过以下过程从十进制(或任何进制)转换为二进制(这是大数实际存储在磁盘上的方式):
-
对于整数部分,简单地将其除以2(字符串除法),直到它为0为止。
在这种情况下,每次除法后的余数编码了数字。 -
对于小数部分,继续乘以2(字符串乘法),直到它为0或进入循环为止。
- 如果变为0,我们只有小数部分而没有重复小数部分。
- 如果进入循环,循环之前的所有数字进入小数部分,其余数字进入重复小数部分。
无论哪种情况,乘法的“余数”/溢出编码了小数部分。
问题出现在从二进制转换为十进制(或任何其他进制)时。我目前的过程如下:
-
通过反转过程并将所有数字的余数相加,乘以2并加上所有数字的余数,得到整数部分。
-
通过添加“余数”/溢出并除以2,得到纯小数(非重复)部分。
然而,对于重复的小数部分,我不知道如何开始。当解码整数或纯小数时,我从值0开始,因为编码过程以值0结束。然而,对于重复小数部分,结束值不是0,所以我不能从0开始并期望得到相同的值。
我不想存储这个停止数字,因为我知道,例如,0.0(0011)(二进制)唯一且明确地映射到0.1(十进制)。任何数字组合都是如此。它们都应该映射到唯一的十进制(或任何其他进制)等价物。
鉴于此,我不想浪费空间存储结束值,因为必须有一种方法可以回到原始值。
那么,我怎么从二进制编码(带有重复数字)转换为基数N的编码(可能带有重复数字)?
如果通用基数不可能,我只对8、10和16进制感兴趣,其中8和16是微不足道的,因为它们是2的幂,所以我真正关心的只是从二进制转换为十进制。
英文:
I currently have a big-num implementation based on rational numbers (with repeating digits) that stores the following (in binary):
- Integer part
- Fraction part
- Repeating fraction part
Some examples (Expressed as <int>.<frac>(<repeating-frac>)):
2.5(base 10):10.1(base 2)2.1(base 10):10.0(0011)(base 2)2.5(3)(base 10):10.(1000)(base 2)
I can convert from base 10 (or any base) to base 2 (which is how the big-num is actually stored on disk) with the following procedure:
-
For the integer part, simply keep dividing it (string division) by 2 until it's 0.
In this case, the remainders after each division encode the number.
-
For the fractional part, keep multiplying (string multiplication) by 2 until it's either 0, or in a loop.
- If we get to 0, we only have a fraction part and no repeating fraction.
- If we get into a loop, all digits before the loop go into the fraction part and all others into the repeating fraction part.
In either case, the "remainder" / overflow of the multiplication encodes the fractional parts.
The problem arises when converting from base 2 to base 10 (or any other base). I have the following procedure currently:
-
Get the integer part fine by reversing the process and multiplying by 2 and adding the remainders of all digits.
-
Get the pure fractional (non-repeating) part by adding the "remainder" / overflow and dividing by 2
However, for the repeating fractional part, I'm at a loss on how to start. When decoding the integer or pure fractional, I start with the value at 0, since the encoding procedures end with the value at 0. However, for the repeating fractional part, the end value is not 0, so I can't start at 0 and expect to get the same value out.
I don't want to store this stop number because I know that, for e.g., 0.0(0011) (base 2) maps uniquely and unambiguously to 0.1 (base 10). The same is true of any digit combination. They should all map to a unique decimal (or any other base) equivalent.
Given this, I don't want to waste space storing the end value, since there must be a way to get back to the original value.
So how can I go from a base 2 encoding (with repeating digits) to a base N encoding (possibly with repeating digits)
If a generic base isn't possible, I'm only really interested in bases 8, 10 and 16, of which 8 and 16 are trivial, as they are powers of 2, so 10 is the only other base I really care about converting to from base 2.
答案1
得分: 0
以下是翻译好的部分:
事实证明,答案相对简单:我们只需执行与从基数N转换为基数2时相同的算法,但不是将基数N的字符串除以2,而是将基数2的字符串除以N。
以下是针对基数N的通用算法,与问题中的算法相同:
- 对于整数部分,只需将其除以N,直到为0为止。
在这种情况下,每次除法后的余数编码了基数N中的数字。
- 对于小数部分,继续乘以N,直到要么为0,要么进入循环。
- 如果达到0,我们只有一个小数部分,没有重复的小数。
- 如果进入循环,循环之前的所有数字都进入小数部分,其他数字都进入重复小数部分。
无论哪种情况,乘法的“余数”/溢出都编码了基数N中的小数部分。
现在,这确实会使实际实现变得复杂,因为通过2进行字符串除法/乘法比通过N进行二进制除法/乘法要简单得多,所以也许可以仅使用字符串操作来实现它,就像问题中的原始解码算法一样,适用于整数和非重复小数部分,但这可能需要比使用二进制操作更多的工作。
英文:
As it turns out, the answer was relatively simple: We simply need to perform the same algorithm as when converting from base N to base 2, but instead of dividing / multiplying a string of base N by 2, we instead divide / multiply a string of base 2 by N.
Here is the same algorithm as in the question, now generic for base N:
-
For the integer part, simply keep dividing it by N until it's 0.
In this case, the remainders after each division encode the number in base N.
-
For the fractional part, keep multiplying by N until it's either 0, or in a loop.
- If we get to 0, we only have a fraction part and no repeating fraction.
- If we get into a loop, all digits before the loop go into the fraction part and all others into the repeating fraction part.
In either case, the "remainder" / overflow of the multiplication encodes the fractional parts in base N.
Now this does complicate the actual implementation, as string division / multiplication by 2 is significantly easier than binary division / multiplication by N, so maybe it's possible to implement it using only string operations, as the original decoding algorithm in the question did for integers and non-repeating fractionals, but that would likely require a lot more work than using binary operations.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论