-
Notifications
You must be signed in to change notification settings - Fork 1
/
fraction.go
82 lines (68 loc) · 1.76 KB
/
fraction.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package humanize
import (
"fmt"
"math"
"strconv"
)
// Fraction takes a decimal (float) value and converts
// it into a string representation of a fractional
// value.
//
// f := humanize.Fraction(0.1)
// fmt.Println(f) => "1/10"
//
func Fraction(decimal float64) string {
if math.IsNaN(decimal) {
return "NaN"
}
precision := float64(calculatePrecision(decimal))
if precision == 0 {
return strconv.FormatFloat(decimal, 'f', 0, 64)
}
factor := math.Pow(10, precision)
denominator := int(factor)
numerator := int(decimal * factor)
// to see if the fraction can be further reduced,
// we will calculate the greatest common factor
if gcf := calculateGCF(numerator, denominator); gcf > 1 {
denominator /= gcf
numerator /= gcf
}
// count amount of "wholes" (integers) the fraction has
// e.g. 6/2 => 3 integers
if wholes := numerator / denominator; wholes != 0 {
numerator -= wholes * denominator
// if wholes are negative
// reverse the numerator
if wholes < 0 {
numerator = -numerator
}
return fmt.Sprintf("%d %d/%d", wholes, numerator, denominator)
}
return fmt.Sprintf("%d/%d", numerator, denominator)
}
// calculateGCF calculates the greatest common factor
// from two integers, using the euclidean algorithm
// https://en.wikipedia.org/wiki/Greatest_common_divisor#Euclidean_algorithm
func calculateGCF(a, b int) int {
for b != 0 {
m := b
b = a % b
a = m
}
return a
}
// calculatePrecision counts how many trailing decimal places
// the decimal value has
func calculatePrecision(decimal float64) int {
// if number is whole, we can't calculate precision
if decimal == math.Trunc(decimal) {
return 0
}
curr, precision := 1.0, 0
for math.Round(decimal*curr)/curr != decimal {
curr *= 10
precision++
}
return precision
}