我编写了一个能够将任何基数(2-36)转换为另一个基数的系统,它可以将任何实数从基数10转换为任何其他基数(2-36)。
我的问题出现在将理性/无理数从10以外的任何基数转换为另一个基数。
我在小数点转换的右侧使用以下算法:
1)在输入中取小数点的右侧(0.xxxxxx --->)并将其乘以您要转换的基数。
2)取大于1的数字(点的左边)并将其添加到转换后的数字的右侧。
3)取出产品的右侧,并在下次重复时使用它作为乘数(它乘以基数)
4)重复直到满意或留下一个整数(右侧为0)。
这很适合将任何浮点数从十进制转换为另一个基数,但显然你不能转换FROM非十进制的基数。
所以我尝试将初始值转换为小数点右边的基数为10,执行数学部分,然后将其转换回原始基数,以便将其添加到输出值时(它转换为添加前的新基地。)
不幸的是,这会返回小数点右侧的错误结果。所以,我的答案在左侧总是正确的,但如果从不是10的基础转换,则在右边不正确。
有没有人对如何使这项工作有任何想法?或许它只是不会?
修改
或者,任何人都可以链接我/告诉我如何将有理十六进制值转换为十进制?仅此一点就足以让我解决这个问题。
解
我找到了一个相当容易解决这个问题的方法,以供将来阅读此问题的其他人使用。
您所要做的就是取小数右侧的数字(无论它是什么基数)并将其转换为十进制(您可以看到如何转换整数here)。然后取出该数字并将其除以其中的最大位值。例如:
A.C
C == 12 (dec)
12 / 16 = .75 (this is the fractional value in decimal)
然后您可以获取该小数十进制值并通过我上面讨论的算法运行它。
感谢大家对此问题的帮助!
答案 0 :(得分:3)
使用浮点意味着您不想执行准确的计算。
只有用基数2,4,8,16 ......编写的数字才能永远在Java floating point值中准确表示(将整数排除在外)。这是由于浮点表示的限制。
只能用基数2,4,5,8,10,16,20,25,32 ......编写的数字可以精确打印在十进制基数中。这是由于decimal number system的限制。
我希望您应该调整一些规则来舍入结果并在整个算法中实施。确保你是圆形而不是截断,否则即使在double
类型的精度足以满足您的目的,或者数字可以的情况下,通过浮点也会得到错误的结果em>准确地代表。
如果要以更高的精度执行计算,请查看BigInteger
类,并以整数形式重新设计算法。或者,使用library来处理分数;这很有用,因为算法的输入始终可以准确地表示为分数。但是,最终它总是归结为定义结果舍入规则并正确实现它们。
修改强>:
正如我从评论中了解到的那样,您希望在读取整个输入之前逐渐发出输出数字。这基本上是可能的,但是
您需要将间隔而不是单个数字保留为“累加器”;例如,如果您到目前为止已经在三元组中读取0.1111
,那么您知道输出位于0.49382716
和0.50617284
之间,并且您甚至无法发出小数点后的第一个十进制数字这个阶段。这对于避免在最“合理”的输入上看到0.4999999992
等输出是必要的。
当读取完整输入时,“舍入”更安全,并根据间隔的上限而不是底部边界发出输出。这种三元组0.1111
将以十进制形式转换为0.5。 (如果限制为十六进制到十进制转换,则可以忽略此项。)
跟踪输入所达到的最大精度(间隔宽度的对数),并确保不会发出比输入保证更多的输出数字。
使用间隔端点(下限和上限)的内部表示,可以安全地处理所需的最大精度。
请记住,即使非常受欢迎的软件偶尔会获得此算法的详细信息wrong,也不会在浮点数据类型中表示任何中间结果,或会截断输入到多个数字,如果它们更长,它们可以安全地表示。
你在问题中提到了无理数,但是无论使用何种基数,每个可用有限(或周期性重复)扩展表示的数字都是有理数。
在从十六进制到十进制的转换中,输出甚至可以始终准确地表示,这允许一些简化,例如无限期地等待下限和上限收敛。