Swift中的十进制到分数转换 [英] Decimal to Fraction conversion in Swift

查看:110
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆