-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathModule1.bas
More file actions
173 lines (134 loc) · 4.56 KB
/
Module1.bas
File metadata and controls
173 lines (134 loc) · 4.56 KB
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
Attribute VB_Name = "FractionCalc"
Sub DecToFrac(DecimalNum As Double, Numerator As Long, Denom As Long)
' The BigNumber constant can be adjusted to handle larger fractional parts
Const bigNumber = 1000
Const SmallNumber = 0.000000000001
Dim Inverse As Double, FractionalPart As Double
Dim WholePart As Long, SwapTemp As Long
Inverse = 1 / DecimalNum
WholePart = Int(Inverse)
FractionalPart = Frac(Inverse)
If 1 / (FractionalPart + SmallNumber) < bigNumber Then
' Notice that DecToFrac is called recursively.
Call DecToFrac(FractionalPart, Numerator, Denom)
Numerator = Denom * WholePart + Numerator
SwapTemp = Numerator
Numerator = Denom
Denom = SwapTemp
Else ' If 1 / (FractionalPart + SmallNumber) > BigNumber
' Recursion stops when the final value of FractionalPart is 0 or
' close enough. SmallNumber is added to prevent division by 0.
Numerator = 1
Denom = Int(Inverse)
End If
End Sub
' This function is used by DecToFrac and DecToProperFact
Function Frac(x As Double) As Double
Frac = Abs(Abs(x) - Int(Abs(x)))
End Function
' This additional procedure handles "improper" fractions and returns
' them in mixed form (a b/c) when the numerator is larger than the denominator
Sub DecToProperFrac(x As Double, a As Long, b As Long, c As Long)
If x > 1 Then a = Int(x)
If Frac(x) <> 0 Then
Call DecToFrac(Frac(x), b, c)
End If
End Sub
Public Function Dec2Frac(ByVal f As Double) As String
On Error GoTo EndIt:
Dim df As Double
Dim lUpperPart As Long
Dim lLowerPart As Long
lUpperPart = 1
lLowerPart = 1
df = lUpperPart / lLowerPart
While (Round(df, 14) <> f)
If (df < f) Then
lUpperPart = lUpperPart + 1
Else
lLowerPart = lLowerPart + 1
lUpperPart = f * lLowerPart
End If
df = lUpperPart / lLowerPart
Wend
Dec2Frac = CStr(lUpperPart) & "/" & CStr(lLowerPart)
Exit Function
EndIt:
Dec2Frac = f
End Function
'convert the script from here, its the best!: http://www.mindspring.com/~alanh/fracs.html
Function GetFractionOld(ByVal d As Double) As String
Dim Denom As Double
Dim Numer As Double
Dim a As Double
Dim b As Double
Dim t As Double
Dim tmpStr As String
tmpStr = CStr(d)
If InStr(1, tmpStr, ",") < 1 Then
GetFraction = ""
Exit Function
End If
tmpStr = Split(tmpStr, ",")(1)
' Get the initial denominator: 1 * (10 ^ decimal portion length)
Denom = (1 * (10 ^ Len(tmpStr)))
' Get the initial numerator: integer portion of the number
Numer = (tmpStr)
Dim i As Long
Dim x As Long
Dim RepeatCheck As String
If Len(tmpStr) > 7 Then
For i = Len(tmpStr) / 2 To 1 Step -1
RepeatCheck = Mid(tmpStr, 1, i)
For x = i + 1 To Len(tmpStr) Step i
If Mid(tmpStr, x, i) = RepeatCheck Then
GoTo ReTime:
Else
Exit For
End If
Next x
Next i
GoTo NotPosible
End If
' Use the Euclidean algorithm to find the gcd
a = Numer
b = Denom
t = 0 ' t is a value holder
GoTo Euclidean:
ReTime:
x = 10 ^ Len(RepeatCheck)
x = x - 1
a = CLng(RepeatCheck)
b = x
Numer = a
Denom = b
t = 0
Euclidean:
' Euclidean algorithm
While b <> 0
t = b
b = FMod(a, b)
a = t
Wend
'Get whole part of the number
Dim Whole As String
Whole = Split(CStr(d), ",")(0)
If Whole = 0 Then
GetFraction = (Numer / a) & "/" & (Denom / a)
Else
GetFraction = Whole & " " & (Numer / a) & "/" & (Denom / a)
End If
' Return our answer
Exit Function
NotPosible:
GetFraction = d
End Function
Public Function FMod(a As Double, b As Double) As Double
FMod = a - Fix(a / b) * b
'http://en.wikipedia.org/wiki/Machine_epsilon
'Unfortunately, this function can only be accurate when `a / b` is outside [-2.22E-16,+2.22E-16]
'Without this correction, FMod(.66, .06) = 5.55111512312578E-17 when it should be 0
If FMod >= -2 ^ -52 And FMod <= 2 ^ -52 Then '+/- 2.22E-16
FMod = 0
End If
End Function