-
Notifications
You must be signed in to change notification settings - Fork 0
/
fraction.go
192 lines (167 loc) · 4.09 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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package math_plus
import (
"fmt"
"github.com/pkg/errors"
"github.com/shopspring/decimal"
"math"
"strconv"
"strings"
)
//goland:noinspection GoSnakeCaseUsage
const DIV_SYMBOL = "/"
//goland:noinspection GoSnakeCaseUsage
var (
ZERO_DENOMINATOR = errors.New("Denominator is 0 ! ")
)
var One = Fraction{
numerator: 1,
denominator: 1,
}
var Zero = Fraction{
numerator: 0,
denominator: 1,
}
// Fraction 分数
type Fraction struct {
// 分子
numerator int64
// 分母
denominator int64
}
// String 格式化输出
func (f Fraction) String() string {
return fmt.Sprintf("%v%s%v", f.numerator, DIV_SYMBOL, f.denominator)
}
// Float64 格式化输出
func (f Fraction) Float64() float64 {
return float64(f.numerator) / float64(f.denominator)
}
// ToRealFraction 约分
func (f Fraction) ToRealFraction() Fraction {
gcd := GreatestCommonDivisor(f.numerator, f.denominator)
f.numerator /= gcd
f.denominator /= gcd
return f
}
// ToFakeFraction 真分数扩大
func (f Fraction) ToFakeFraction(multiple int64) Fraction {
return newFraction(f.numerator*multiple, f.denominator*multiple)
}
func (f Fraction) IsZero() bool {
if f.numerator == 0 {
return true
}
return false
}
//Add 加
func (f Fraction) Add(fra Fraction) Fraction {
if fra.denominator == 0 {
return fra
}
lcm := LeastCommonMultiple(f.denominator, fra.denominator)
return newFraction(f.numerator*lcm/f.denominator+fra.numerator*lcm/fra.denominator, lcm).ToRealFraction()
}
//Sub 减
func (f Fraction) Sub(fra Fraction) Fraction {
fra.numerator = -fra.numerator
return f.Add(fra)
}
//Mul 乘
func (f Fraction) Mul(fra Fraction) Fraction {
return newFraction(f.numerator*fra.numerator, f.denominator*fra.denominator).ToRealFraction()
}
func (f Fraction) MulInt64(n int64) Fraction {
return newFraction(f.numerator*n, f.denominator)
}
// Div 除
func (f Fraction) Div(fra Fraction) Fraction {
return f.Mul(fra.Reverse())
}
// New 创建假分数
func New(n, d int64) (Fraction, error) {
if d == 0 {
return Fraction{}, ZERO_DENOMINATOR
}
return newFraction(n, d), nil
}
//Reverse 倒数
func (f Fraction) Reverse() Fraction {
return newFraction(f.denominator, f.numerator)
}
func newFraction(n, d int64) Fraction {
return Fraction{
numerator: n,
denominator: d,
}
}
// NewFromFloat 从小数创建
func NewFromFloat(n, d float64) (Fraction, error) {
if d == 0.0 {
return Fraction{}, ZERO_DENOMINATOR
}
nn, err := FloatToFraction(n)
if err != nil {
return Fraction{}, err
}
dd, err := FloatToFraction(d)
if err != nil {
return Fraction{}, err
}
return nn.Div(dd), nil
}
// NewFromFloatByDecimal 使用decimal 计算,结果可能不完全正确
func NewFromFloatByDecimal(n, d float64) Fraction {
nn, dd := decimal.NewFromFloat(n), decimal.NewFromFloat(d)
result, _ := nn.Div(dd).Float64()
f, _ := NewFromFloat(result, 1)
return f
}
// NewFromString 从字符串创建,字符串中分子分母需为整数
// 支持 int/int int float
func NewFromString(str string) (Fraction, error) {
fraction := Fraction{}
arr := strings.Split(str, "/")
if len(arr) == 1 {
n, err := strconv.Atoi(str)
if err != nil {
v, err := strconv.ParseFloat(str, 64)
if err == nil {
return FloatToFraction(v)
}
return Fraction{0, 1}, err
}
return Fraction{int64(n), 1}, nil
}
if len(arr) != 2 {
return fraction, errors.New(" Fraction string is invalid! ")
}
n, err := strconv.ParseInt(arr[0], 10, 64)
if err != nil {
return Fraction{}, errors.New("Numerator is invalid! ")
}
d, err := strconv.ParseInt(arr[1], 10, 64)
if err != nil {
return Fraction{}, errors.New("Denominator is invalid! ")
}
if d == 0 {
return Fraction{}, ZERO_DENOMINATOR
}
return newFraction(n, d).ToRealFraction(), nil
}
func FloatToFraction(f float64) (Fraction, error) {
if f == 0 {
return newFraction(0, 1), nil
} else {
str := fmt.Sprint(f)
if strings.Contains(str, ".") {
arr := strings.Split(str, ".")
n, err := strconv.ParseInt(arr[0]+arr[1], 10, 64)
if err != nil {
return Fraction{}, err
}
return newFraction(n, int64(math.Pow10(len(arr[1])))), nil
} else {
return newFraction(int64(int(f)), 1), nil
}
}
}