Swift中的十进制到分数转换 [英] Decimal to Fraction conversion in Swift
问题描述
我正在构建一个计算器,并希望它自动将每个小数转换为分数。因此,如果用户计算答案为0.333333 ...的表达式,则返回1/3。对于0.25,它将返回1/4。使用GCD,如此处所示(十进制到分数转换),我已经找到了如何转换任何有理的,终止的十进制小数,但这不适用于重复的任何小数(如.333333)。
I am building a calculator and want it to automatically convert every decimal into a fraction. So if the user calculates an expression for which the answer is "0.333333...", it would return "1/3". For "0.25" it would return "1/4". Using GCD, as found here (Decimal to fraction conversion), I have figured out how to convert any rational, terminating decimal into a decimal, but this does not work on any decimal that repeats (like .333333).
堆栈溢出的每个其他函数都在Objective-C中。但我需要一个快速应用程序中的功能!所以这个翻译版本( https://stackoverflow.com/a/13430237/5700898 )会很好!
Every other function for this on stack overflow is in Objective-C. But I need a function in my swift app! So a translated version of this (https://stackoverflow.com/a/13430237/5700898) would be nice!
如何将有理或重复/无理小数转换为分数的任何想法或解决方案(即将0.1764705882 ...转换为3 / 17)会很棒!
Any ideas or solutions on how to convert a rational or repeating/irrational decimal to a fraction (i.e. convert "0.1764705882..." to 3/17) would be great!
推荐答案
如果你想将计算结果显示为有理数
那么只有100%正确的解决方案是在所有计算中使用有理算法,即所有中间值都存储为一对整数(分子,分母)
,所有加法,乘法,除法等都是使用理性
数的规则完成的。
If you want to display the results of calculations as rational numbers
then the only 100% correct solution is to use rational arithmetic throughout all calculations, i.e. all intermediate values are stored as a pair of integers (numerator, denominator)
, and all additions, multiplications, divisions, etc are done using the rules for rational
numbers.
只要将结果分配给二进制浮点数
,例如 Double
,信息丢失。例如,
As soon as a result is assigned to a binary floating point number
such as Double
, information is lost. For example,
let x : Double = 7/10
存储在 x
近似值 0.7
,因为这个数字不能
完全表示为 Double
。从
stores in x
an approximation of 0.7
, because that number cannot
be represented exactly as a Double
. From
print(String(format:"%a", x)) // 0x1.6666666666666p-1
可以看到 x
保留值
0x16666666666666 * 2^(-53) = 6305039478318694 / 9007199254740992
≈ 0.69999999999999995559107901499373838305
所以 x
的正确表示形式为理性数字为
6305039478318694/9007199254740992
,但这当然不是您期望的
。您期望的是 7/10
,但还有另一个问题:
So a correct representation of x
as a rational number would be
6305039478318694 / 9007199254740992
, but that is of course not what
you expect. What you expect is 7/10
, but there is another problem:
let x : Double = 69999999999999996/100000000000000000
为分配完全相同的值x
,在 Double
的精度范围内与
0.7
无法区分。
assigns exactly the same value to x
, it is indistinguishable from
0.7
within the precision of a Double
.
所以 x
应显示为 7/10
或 69999999999999996/100000000000000000
?
如上所述,使用有理算法将是完美的解决方案。
如果这不可行,那么你可以将 Double
转换回
一个具有给定精度的有理数 。
(以下摘自 LCM算法斯威夫特的双打。)
As said above, using rational arithmetic would be the perfect solution.
If that is not viable, then you can convert the Double
back to
a rational number with a given precision.
(The following is taken from Algorithm for LCM of doubles in Swift.)
续分数
是创建(有限或无限)分数序列的有效方法 h n / k n 这是给定实数 x ,
的任意良好近似值,这里是Swift中可能的实现:
Continued Fractions are an efficient method to create a (finite or infinite) sequence of fractions hn/kn that are arbitrary good approximations to a given real number x, and here is a possible implementation in Swift:
typealias Rational = (num : Int, den : Int)
func rationalApproximationOf(x0 : Double, withPrecision eps : Double = 1.0E-6) -> Rational {
var x = x0
var a = floor(x)
var (h1, k1, h, k) = (1, 0, Int(a), 1)
while x - a > eps * Double(k) * Double(k) {
x = 1.0/(x - a)
a = floor(x)
(h1, k1, h, k) = (h, k, h1 + Int(a) * h, k1 + Int(a) * k)
}
return (h, k)
}
示例:
rationalApproximationOf(0.333333) // (1, 3)
rationalApproximationOf(0.25) // (1, 4)
rationalApproximationOf(0.1764705882) // (3, 17)
默认精度为1.0E-6,但您可以根据需要进行调整:
The default precision is 1.0E-6, but you can adjust that to your needs:
rationalApproximationOf(0.142857) // (1, 7)
rationalApproximationOf(0.142857, withPrecision: 1.0E-10) // (142857, 1000000)
rationalApproximationOf(M_PI) // (355, 113)
rationalApproximationOf(M_PI, withPrecision: 1.0E-7) // (103993, 33102)
rationalApproximationOf(M_PI, withPrecision: 1.0E-10) // (312689, 99532)
Swift 3 版本:
typealias Rational = (num : Int, den : Int)
func rationalApproximation(of x0 : Double, withPrecision eps : Double = 1.0E-6) -> Rational {
var x = x0
var a = x.rounded(.down)
var (h1, k1, h, k) = (1, 0, Int(a), 1)
while x - a > eps * Double(k) * Double(k) {
x = 1.0/(x - a)
a = x.rounded(.down)
(h1, k1, h, k) = (h, k, h1 + Int(a) * h, k1 + Int(a) * k)
}
return (h, k)
}
示例:
rationalApproximation(of: 0.333333) // (1, 3)
rationalApproximation(of: 0.142857, withPrecision: 1.0E-10) // (142857, 1000000)
这篇关于Swift中的十进制到分数转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!