Decimal to Fraction conversion in Swift
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.
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
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
one can see that x
holds the value
0x16666666666666 * 2^(-53) = 6305039478318694 / 9007199254740992
≈ 0.69999999999999995559107901499373838305
So a correct representation of x
as a rational number would be6305039478318694 / 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
assigns exactly the same value to x
, it is indistinguishable from0.7
within the precision of a Double
.
So should x
be displayed as 7/10
or as 69999999999999996/100000000000000000
?
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.)
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)
}
Examples:
rationalApproximationOf(0.333333) // (1, 3)
rationalApproximationOf(0.25) // (1, 4)
rationalApproximationOf(0.1764705882) // (3, 17)
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 version:
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)
}
Examples:
rationalApproximation(of: 0.333333) // (1, 3)
rationalApproximation(of: 0.142857, withPrecision: 1.0E-10) // (142857, 1000000)
Or – as suggested by @brandonscript – with a struct Rational
and an initializer:
struct Rational {
let numerator : Int
let denominator: Int
init(numerator: Int, denominator: Int) {
self.numerator = numerator
self.denominator = denominator
}
init(approximating x0: Double, withPrecision eps: Double = 1.0E-6) {
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)
}
self.init(numerator: h, denominator: k)
}
}
Example usage:
print(Rational(approximating: 0.333333))
// Rational(numerator: 1, denominator: 3)
print(Rational(approximating: .pi, withPrecision: 1.0E-7))
// Rational(numerator: 103993, denominator: 33102)
How to turn decimal into a fraction - Swift
For this to work every time, you want to use the Euclidian Algorithm, which in swift looks like this:
func simplify(top:Int, bottom:Int) -> (newTop:Int, newBottom:Int) {
var x = top
var y = bottom
while (y != 0) {
var buffer = y
y = x % y
x = buffer
}
var hcfVal = x
var newTopVal = top/hcfVal
var newBottomVal = bottom/hcfVal
return(newTopVal, newBottomVal)
}
You should just be able to add this to your program, then call it with:
simplify(5,10)
...returning 1 and 2. Hope this helps anyone else trying to find a simpler answer to this question.
How do I convert a fractional decimal to a whole number in Swift
Here is an example:
let a = 0.90
let fractionalPart = a.truncatingRemainder(dividingBy: 1.0)
let modifiedFractionalPart = Int(fractionalPart * 100.0)
let string = String(modifiedFractionalPart)
// prints 90
If you aren't allowed to multiply by 100.0
, meaning you don't actually have to limit your fractional part to two decimal places, rather you need to have the whole part after the .
then use the following:
let a = 0.09017
let fractionalPart = String(a).components(separatedBy: ".")[1] // "09017"
Then if you have to convert it to an Int
just do:
let fractionalPartInt = Int(fractionalPart) // 09017
Using iOS NumberFormatter to format decimal into fraction representation
No. You would need to implement your own Rational Formatter. You can use this answer from Martin R as a starting point. You can do something like:
class RationalFormatter: Formatter {
let precision: Double = 1.0E-6
override public func string(for obj: Any?) -> String? {
guard let value = obj as? Double else { return nil }
let whole = modf(value).0
var x = modf(value).1
var a = x.rounded(.down)
var (h1, k1, numerator, denominator) = (1, 0, Int(a), 1)
while x - a > precision * Double(denominator) * Double(denominator) {
x = 1.0/(x - a)
a = x.rounded(.down)
(h1, k1, numerator, denominator) = (numerator, denominator, h1 + Int(a) * numerator, k1 + Int(a) * denominator)
}
var string = ""
if whole < 0 || numerator < 0 {
string += "-"
}
if whole != 0 {
string += String(Int(abs(whole)))
}
if whole != 0 && numerator != 0 {
string += " "
}
if numerator != 0 {
string += "\(abs(numerator))/\(abs(denominator))"
}
return string
}
}
Usage:
let double = 2.375
let rationalFormatter = RationalFormatter()
let formatted = rationalFormatter.string(for: double) // "2 3/8"
Converting fractions into decimals from UITextField in Swift
You need to parse and then calculate the fraction by yourself in a method or extension. One way of doing is as follows:
extension UITextField {
var fraction: Float {
var comps = text.componentsSeparatedByString("/")
//Do some validation here so as to check the correct format of fraction text.
var op1 = NSString(string: comps[0]).floatValue
var op2 = NSString(string: comps[1]).floatValue
return op1/op2
}
}
Decimal to fraction conversion
A decimal number is a fraction whose denominator is a power of ten (and similarly for any number base). So 0.34 is 34/100. Now just cancel the common factor, i.e. divide both numerator and denominator by their greatest common divisor.
You can find the GCD with a standard algorithm, which I leave to you to find.
Related Topics
Add "Edit in Excel" or "Edit Photo" Extension
In Firebase, How to Query the Most Recent 10 Child Nodes
How to Apply a Vignette Cifilter to a Live Camera Feed in iOS
Is There an iPhone Se Simulator for Xcode 11, iOS 13
How to Display a Uipopoverview as a Annotation to the Map View? (iPad)
Difference Between _ and Self. in Objective-C
Showing Pushviewcontroller Animation Look Like Presentmodalviewcontroller
Can Not Save File Inside Tmp Directory
Smart-Search for Parse Usernames in Swift Not Working
Does This App Use the Advertising Identifier (IDFA)? - Admob 6.8.0
How to Make View the Size of Another View in Swiftui
How to Attach Debugger to iOS App After Launch
Check If Uicolor Is Dark or Bright
Cocoapods: Failed to Connect to Github to Update the Cocoapods/Specs Specs Repo
How to Check If a File Exists in Documents Folder
How to Export Data to a CSV File with iOS
Swift- Change Font on an HTML String That Has Its Own Styles