@kon, this is beautiful, well thought out and very efficient, thank you so much for posting it.kon wrote:This factors function should be more efficient
I'll update my post above.
@FanaticGuru, your understanding of the task in hand is impeccable.
@kon, this is beautiful, well thought out and very efficient, thank you so much for posting it.kon wrote:This factors function should be more efficient
this code should take care of every possible way as it looks for the numbers and not the separatorsFanaticGuru wrote:Right now I am having more trouble getting my Fraction2Decimal script working correctly which sounds stupid as it is basically nothing but a practice in RegEx to handle every way I can think of writing: feet and/or inches with fractional feet or inches and weird ways I have seen stuff.
Code: Select all
data =
(
0' 8-31/32"
2'
3' 0"
44' 11 31/32
4' 10" 31/32
4' 9 31/32"
0' 8-31/32"
11" 31/32
31/32
)
loop, parse, data, `n
MsgBox % fr2dec(A_LoopField)
return
fr2dec(Fr) {
while pos := RegExMatch(Fr, "\d+", m, pos?pos+StrLen(m):1)
Nos := m . (A_Index=1?"":"`n") Nos
No := StrSplit(Nos, "`n")
IfInString, Fr, /
denominator := No[1] , numerator := No[2] ,inches := No[3]?No[3]:0 , feet := No[4]?No[4]:0
else if No[2]
denominator := 1 , numerator := 0 ,inches := No[1]?No[1]:0 , feet := No[2]
else
denominator := 1 , numerator := 0 ,inches := 0 , feet := No[1]
;~ ToolTip % feet "' " inches """ " numerator "/" denominator
return feet + (inches + numerator/denominator) / 12
}
AlphaBravo wrote:I tried your function and it struggled for few of my trials, here is my own attemptCode: Select all
numbers := [14.285714, 1.2142857, 100/7] QPX(1) for each, n in numbers res1 .= Dec2Fr(n) "`n" t1 := "`nt= " QPX(0) " seconds" MsgBox % res1 t1 return Dec2Fr(n){ PrimNo := [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97] neg := n && n < 0 ? "-" : "" n := Abs(n) whole := Floor(n) ? Floor(n)" " : "" if (n = whole) || !n return neg floor(n) dec := n - floor(n) while (dec > floor(dec)) dec*=10, dec := RTrim(RTrim(dec,0),.) exp := StrLen(dec) numerator:=floor(dec) denominator := 10**exp fr := floor(numerator) "/" floor(denominator) for each, v in PrimNo if (Abs(round(n*v) - n*v) < 0.0001) ; close enough return neg whole floor(Mod(n*v,v)) "/" v for each, f in Factors(numerator) if !Mod(numerator,f) && !Mod(denominator,f) fr := floor(numerator/f) "/" floor(denominator/f) return neg whole fr } Factors(n,Delim:=""){ ; http://ahkscript.org/boards/viewtopic.php?f=6&t=994#p7404 factors := {}, factors[n] := n, d := 1, s := Floor(Sqrt(n)) while (++d<=s) if !Mod(n,d) factors[d] := d, factors[n // d] := n // d if Delim for key, val in factors res.=(res?Delim:"") key return Delim?res:factors }
QPX is not really part of the code, it's a performance query.Guest10 wrote:when i ran this it said: QPX(1) ... Error: Call to nonexistant function.!
That is exactly what I thought of when I was laying in bed last night. I don't need to figure out complex RegEx. The input is basically 1 to 4 numbers separated by "stuff". If I look at it that way I should be able to make it very versatile.AlphaBravo wrote:this code should take care of every possible way as it looks for the numbers and not the separators
you're just a Fanatic geek like the rest of us here!FanaticGuru wrote:May sound strange but I am not going to look at your code and do what I have in my head and then compare.
Code: Select all
Fractions := [
(Join,
"4/8"
"1 4/8"
"-2'6"" 24/8"
"6'8"""
"5 ft 9 in"
"1ft6in"
"7 feet 8 / 10 inches"
"9 1 /4 feet"
"9 1 /4 inches"
"9 - 3 feet/inches"
"9 feet and 3 1/4 inches"
"4 and 8 out of 10 feet"
)]
for index, Fraction in Fractions
MsgBox % Fraction2Decimal(Fraction)
Esc::ExitApp
Fraction2Decimal(Fraction)
{
if Fraction is number
return Fraction
Num := {}
N := 0
D := 1
if RegExMatch(Fraction, "^\s*-")
Has_Neg := true
if RegExMatch(Fraction, "i)feet|foot|ft|'")
Has_Feet := true
if RegExMatch(Fraction, "i)inch|in|""")
Has_Inches := true
if RegExMatch(Fraction, "i)/|of|div")
Has_Fraction := true
RegExMatch(Fraction,"^\D*(\d*)\D*(\d*)\D*(\d*)\D*(\d*)",Match)
Loop 4
if Match%A_Index%
Num.Insert(Match%A_Index%)
if Has_Fraction
{
N := Num[Num.MaxIndex()-1]
D := Num[Num.MaxIndex()]
}
Output := (Num.MaxIndex() = 2 ? 0 : Num[1]) + N / D
if (Has_Feet & Has_Inches)
if (Num.MaxIndex() = 2)
Output := Num[1] + Num[2] /12
else
Output := Num[1] + ((Num.MaxIndex() = 3 ? 0:Num[2]) + N / D) / 12
return (Has_Neg ? "-":"") Output
}
;}
Code: Select all
GCD(A, B)
{
if !B
return A
else
return GCD(B, Mod(A,B))
}
Code: Select all
while X != 1
{
X := GCD(Numerator,Denominator)
Numerator := Numerator / X
Denominator := Denominator / X
}
Code: Select all
QPX( True )
Loop, 100000 {
Random, Var1, 1, 100000
Random, Var2, 1, 100000
GCD1(Var1, Var2)
}
MsgBox, % "GCD1`n" QPX( False )
QPX( True )
Loop, 100000 {
Random, Var1, 1, 100000
Random, Var2, 1, 100000
GCD2(Var1, Var2)
}
MsgBox, % "GCD2`n" QPX( False )
QPX( True )
Loop, 100000 {
Random, Var1, 1, 100000
Random, Var2, 1, 100000
GCD3(Var1, Var2)
}
MsgBox, % "GCD3`n" QPX( False )
GCD1(A, B)
{
if !B
return A
else
return GCD1(B, Mod(A,B))
}
;http://www.autohotkey.com/board/topic/24841-least-common-multiple-and-greatest-common-factor/#entry161113
;by Laszlo
GCD2(a,b) { ; Euclidean GCD
Return b=0 ? Abs(a) : GCD2(b, mod(a,b))
}
;https://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations
GCD3(a, b) {
while (b != 0) {
t := b
b := Mod(a, b)
a := t
}
return, a
}
QPX( N=0 ) { ; Wrapper for QueryPerformanceCounter()by SKAN | CD: 06/Dec/2009
Static F,A,Q,P,X ; www.autohotkey.com/forum/viewtopic.php?t=52083 | LM: 10/Dec/2009
If ( N && !P )
Return DllCall("QueryPerformanceFrequency",Int64P,F) + (X:=A:=0) + DllCall("QueryPerformanceCounter",Int64P,P)
DllCall("QueryPerformanceCounter",Int64P,Q), A:=A+Q-P, P:=Q, X:=X+1
Return ( N && X=N ) ? (X:=X-1)<<64 : ( N=0 && (R:=A/X/F) ) ? ( R + (A:=P:=X:=0) ) : 1
}
If we are shooting for best speed then I need to put my twist on it.kon wrote:I've done some speed tests on the GCD function in the past and found that the recursive functions are about 5x slower than using a while-loop like the function I posted above. (But the one-liner by Laszlo has a very high coolness factor.) Here they are with some speed tests:
Code: Select all
GCD(A, B)
{
while B
T := B, B := Mod(A, B), A := T
return A
}
Code: Select all
QPX( True )
Loop, 1000000 {
Random, Var1, 1, 100000
Random, Var2, 1, 100000
GCD1(Var1, Var2)
}
MsgBox, % "GCD1`n" QPX( False )
QPX( True )
Loop, 1000000 {
Random, Var1, 1, 100000
Random, Var2, 1, 100000
GCD2(Var1, Var2)
}
MsgBox, % "GCD2`n" QPX( False )
;https://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations
GCD1(a, b) {
while (b != 0) {
t := b
b := Mod(a, b)
a := t
}
return, a
}
GCD2(a, b)
{
while b
t := b, b := Mod(a, b), a := t
return, a
}
QPX( N=0 ) { ; Wrapper for QueryPerformanceCounter()by SKAN | CD: 06/Dec/2009
Static F,A,Q,P,X ; www.autohotkey.com/forum/viewtopic.php?t=52083 | LM: 10/Dec/2009
If ( N && !P )
Return DllCall("QueryPerformanceFrequency",Int64P,F) + (X:=A:=0) + DllCall("QueryPerformanceCounter",Int64P,P)
DllCall("QueryPerformanceCounter",Int64P,Q), A:=A+Q-P, P:=Q, X:=X+1
Return ( N && X=N ) ? (X:=X-1)<<64 : ( N=0 && (R:=A/X/F) ) ? ( R + (A:=P:=X:=0) ) : 1
}
I still think you should perform rounding, check the result of Fraction2Decimal(100/7)FanaticGuru wrote:Removed any default rounding
I assume you are talking about doing:AlphaBravo wrote:I still think you should perform rounding, check the result of Fraction2Decimal(100/7)FanaticGuru wrote:Removed any default rounding
with regards to Fraction2Decimal , you interpret 4/8 as 0.5 Ft, and I interpreted as 0.5 Inch
That was a silly mistake.Relayer wrote:Decimal2Fraction(1.5,"AA") gives me 1'-7''
Relayer
Code: Select all
;Convert decimal feet to Feet-Inches-Fraction
; DecFt Decimal feet
; Precision Round to the nearsest 1/Precision of an inch
DecFtToArch(DecFt, Precision:=16) {
Ft := Floor(DecFt), In := 12 * Mod(DecFt, 1), UpperLimit := 1 - (HalfPrecision := 0.5 / Precision)
Fraction := Mod(In, 1), In := Floor(In)
if (Fraction >= UpperLimit) {
In++, Fraction := ""
if (In = 12)
In := 0, Ft++
}
else if (Fraction < HalfPrecision)
Fraction := ""
else
Fraction := GetFraction(Precision, Fraction, UpperLimit)
return, (Ft ? Ft "'-" : "") In Fraction """"
}
;Convert decimal inches to Inches-Fraction
; DecIn Decimal inches
; Precision Round to the nearsest 1/Precision of an inch
DecInToArch(DecIn, Precision:=16) {
In := Floor(DecIn), UpperLimit := 1 - (HalfPrecision := 0.5 / Precision), Fraction := Mod(DecIn, 1)
if (Fraction >= UpperLimit)
In++, Fraction := ""
else if (Fraction < HalfPrecision)
Fraction := ""
else
Fraction := GetFraction(Precision, Fraction, UpperLimit)
return, (In ? In : "") Fraction """"
}
GetFraction(Precision, Fraction, UpperLimit) {
Step := 1 / Precision
Loop, % Precision - 1 {
if (Fraction >= UpperLimit - (A_Index * Step)) {
gcd := gcd(Precision, n := Precision - A_Index)
return, "-" n // gcd "/" Precision // gcd
}
}
}
gcd(a, b) {
while b
t := b, b := Mod(a, b), a := t
return, a
}
Code: Select all
;Rounded to the nearest 16th of an inch by default
MsgBox, % DecFtToArch(1.23456)
MsgBox, % DecInToArch(19.2)
;Rounded to the nearest 1000000th of an inch
SetFormat, Float, 0.7
MsgBox, % DecFtToArch(123.4581236, 1000000)
;Rounded to the nearest 45678th of an inch
MsgBox, % DecInToArch(123.4581236, 45678)
Return to “Scripts and Functions (v1)”
Users browsing this forum: No registered users and 261 guests