Post Reply 
Round a decimal value to fraction using Farey series
12-11-2013, 08:44 PM (This post was last modified: 12-13-2013 06:10 AM by patrice.)
Post: #1
Round a decimal value to fraction using Farey series
Round Vl to best fraction with denominator smaller than DMax
Code:
EXPORT FareyMax(Vl, DMax)
// Round a Vl to the best fraction with denominator < DMax
BEGIN
LOCAL VlE, Tmp;
LOCAL DbN,DbD, FnN,FnD, RsN,RsD,RsE;
VlE:= ABS(Vl);
DbN:= IP(VlE); DbD:=1; FnN:=DbN+1; FnD:=1;
RsN:= ROUND(VlE,0); RsD:= 1; RsE:= ABS(VlE-(RsN/RsD));
WHILE DbD+FnD <= DMax DO
  Tmp:= (DbN+FnN)/(DbD+FnD);
  IF RsE > ABS(VlE-Tmp) THEN RsN:= (DbN+FnN); RsD:= (DbD+FnD); RsE:= ABS(VlE-(RsN/RsD)); END;
  IF Tmp < VlE THEN DbN:= (DbN+FnN); DbD:= (DbD+FnD); ELSE FnN:= (DbN+FnN); FnD:= (DbD+FnD); END;
END;
RETURN "'"+SIGN(Vl)*RsN+"/"+RsD+"'";
END;

Round Vl to best fraction with Vl-Error < Fraction < Vl+Error
Code:
EXPORT FareyDelta(Vl, Error)
// round Vl to the smallest fraction with |Vl - fraction| < Error
BEGIN
LOCAL VlE, Tmp;
LOCAL DbN,DbD, FnN,FnD, RsN,RsD,RsE;
VlE:= ABS(Vl);
DbN:= IP(VlE); DbD:=1; FnN:=DbN+1; FnD:=1;
RsN:= ROUND(VlE,0); RsD:= 1; RsE:= ABS(VlE-(RsN/RsD));
WHILE RsE > Error DO
  Tmp:= (DbN+FnN)/(DbD+FnD);
  IF RsE > ABS(VlE-Tmp) THEN RsN:= (DbN+FnN); RsD:= (DbD+FnD); RsE:= ABS(VlE-(RsN/RsD)); END;
  IF Tmp < VlE THEN DbN:= (DbN+FnN); DbD:= (DbD+FnD); ELSE FnN:= (DbN+FnN); FnD:= (DbD+FnD); END;
END;
RETURN "'"+SIGN(Vl)*RsN+"/"+RsD+"'";
END;

Patrice
“Everything should be made as simple as possible, but no simpler.” Albert Einstein
Find all posts by this user
Quote this message in a reply
12-13-2013, 04:18 AM
Post: #2
RE: Round a decimal value to fraction using Farey series
FYI: The INT (integer-part) function no longer exists in the current firmware. You must replace INT with IP for the above programs to work.

<0|ɸ|0>
-Joe-
Visit this user's website Find all posts by this user
Quote this message in a reply
12-13-2013, 06:13 AM (This post was last modified: 12-13-2013 06:24 AM by patrice.)
Post: #3
RE: Round a decimal value to fraction using Farey series
Ooops, forgot to recheck before posting.
Done. Note the simplified RETURN

Patrice
“Everything should be made as simple as possible, but no simpler.” Albert Einstein
Find all posts by this user
Quote this message in a reply
12-21-2013, 09:04 PM
Post: #4
RE: Round a decimal value to fraction using Farey series
Here is an update.
The program is made for Home but should work in CAS
It list all successives fractions in terminal as they get better
Exemple: FareyMax(π;10000)
Code:
EXPORT FareyMax(Vl, DMax)
// Round a Vl to the best fraction with denominator < DMax
BEGIN
LOCAL VlE, Tmp;
LOCAL DbN,DbD, FnN,FnD, RsN,RsD,RsE;
PRINT();
VlE:= ABS(Vl);
DbN:= IP(VlE); DbD:=1; FnN:=DbN+1; FnD:=1;
RsN:= ROUND(VlE,0); RsD:= 1; RsE:= ABS(VlE-(RsN/RsD));
PRINT(SIGN(Vl)*RsN+"/"+RsD);
WHILE DbD+FnD <= DMax DO
  Tmp:= (DbN+FnN)/(DbD+FnD);
  IF RsE > ABS(VlE-Tmp) THEN RsN:= (DbN+FnN); RsD:= (DbD+FnD); RsE:= ABS(VlE-(RsN/RsD)); PRINT(SIGN(Vl)*RsN+"/"+RsD);END;
  IF Tmp < VlE THEN DbN:= (DbN+FnN); DbD:= (DbD+FnD); ELSE FnN:= (DbN+FnN); FnD:= (DbD+FnD); END;
END;
RETURN "'"+SIGN(Vl)*RsN+"/"+RsD+"'";
// RETURN EXPR("QUOTE("+SIGN(Vl)*RsN+"/"+RsD+")");
END;

Patrice
“Everything should be made as simple as possible, but no simpler.” Albert Einstein
Find all posts by this user
Quote this message in a reply
06-07-2014, 02:21 AM (This post was last modified: 06-17-2014 12:44 AM by patrice.)
Post: #5
RE: Round a decimal value to fraction using Farey series
Update for Rev 6030
Code:
#pragma mode( separator(.,;) integer(h64) )
// rev 6030 update
EXPORT RoundFract(V, F)
BEGIN
RETURN ROUND(V*F,0)/F;
END;

EXPORT FareyMax(Vl, DMax)
// Round a Vl to the best fraction with denominator < DMax
BEGIN
LOCAL VlE, Tmp;
LOCAL DbN,DbD, FnN,FnD, RsN,RsD,RsE;
PRINT();
VlE:= ABS(Vl);
DbN:= IP(VlE); DbD:=1; FnN:=DbN+1; FnD:=1;
RsN:= ROUND(VlE,0); RsD:= 1; RsE:= ABS(VlE-(RsN/RsD));
PRINT(STRING(SIGN(Vl)*RsN,2,0)+"/"+STRING(RsD,2,0));
WHILE DbD+FnD <= DMax DO
  Tmp:= (DbN+FnN)/(DbD+FnD);
  IF RsE > ABS(VlE-Tmp) THEN RsN:= (DbN+FnN); RsD:= (DbD+FnD); RsE:= ABS(VlE-(RsN/RsD)); PRINT(STRING(SIGN(Vl)*RsN,2,0)+"/"+STRING(RsD,2,0));END;
  IF Tmp < VlE THEN DbN:= (DbN+FnN); DbD:= (DbD+FnD); ELSE FnN:= (DbN+FnN); FnD:= (DbD+FnD); END;
END;
// RETURN "'"+STRING(SIGN(Vl)*RsN,2,0)+"/"+STRING(RsD,2,0)+"'";
RETURN EXPR("QUOTE("+STRING(SIGN(Vl)*RsN,2,0)+"/"+STRING(RsD,2,0)+")");
END;

EXPORT FareyDelta(Vl, Error)
// round Vl to the smallest fraction with |Vl - fraction| < Error
BEGIN
LOCAL VlE, Tmp;
LOCAL DbN,DbD, FnN,FnD, RsN,RsD,RsE;
VlE:= ABS(Vl);
DbN:= IP(VlE); DbD:=1; FnN:=DbN+1; FnD:=1;
RsN:= ROUND(VlE,0); RsD:= 1; RsE:= ABS(VlE-(RsN/RsD));
WHILE RsE > Error DO
  Tmp:= (DbN+FnN)/(DbD+FnD);
  IF RsE > ABS(VlE-Tmp) THEN RsN:= (DbN+FnN); RsD:= (DbD+FnD); RsE:= ABS(VlE-(RsN/RsD)); END;
  IF Tmp < VlE THEN DbN:= (DbN+FnN); DbD:= (DbD+FnD); ELSE FnN:= (DbN+FnN); FnD:= (DbD+FnD); END;
END;
// RETURN "'"+STRING(SIGN(Vl)*RsN,2,0)+"/"+STRING(RsD,2,0)+"'";
RETURN EXPR("QUOTE("+STRING(SIGN(Vl)*RsN,2,0)+"/"+STRING(RsD,2,0)+")");
END;

EXPORT FareyDisp(Vl,Rnd)
// round Vl to the smallest fraction that match the display
BEGIN
LOCAL VlE, Tmp;
LOCAL DbN,DbD, FnN,FnD, RsN,RsD,RsE;
VlE:= ABS(ROUND(Vl,Rnd));
DbN:= IP(VlE); DbD:=1; FnN:=DbN+1; FnD:=1;
RsN:= ROUND(VlE,0); RsD:= 1; RsE:= ABS(VlE-ROUND(RsN/RsD,Rnd));
WHILE RsE > 0 DO
  Tmp:= (DbN+FnN)/(DbD+FnD);
  IF RsE > ABS(VlE-Tmp) THEN RsN:= (DbN+FnN); RsD:= (DbD+FnD); RsE:= ABS(VlE-ROUND(RsN/RsD,Rnd)); END;
  IF Tmp < VlE THEN DbN:= (DbN+FnN); DbD:= (DbD+FnD); ELSE FnN:= (DbN+FnN); FnD:= (DbD+FnD); END;
END;
RETURN EXPR("QUOTE("+STRING(SIGN(Vl)*RsN,2,0)+"/"+STRING(RsD,2,0)+")");
END;
Nota: if you want FareyMax to be a simple function, just remove all PRINT commands from source code.

Patrice
“Everything should be made as simple as possible, but no simpler.” Albert Einstein
Find all posts by this user
Quote this message in a reply
06-14-2014, 07:01 PM
Post: #6
RE: Round a decimal value to fraction using Farey series
This is great, Patrice!
Visit this user's website Find all posts by this user
Quote this message in a reply
06-17-2014, 12:45 AM
Post: #7
RE: Round a decimal value to fraction using Farey series
Corrected a typo in my last message (in function FareyDelta)

Patrice
“Everything should be made as simple as possible, but no simpler.” Albert Einstein
Find all posts by this user
Quote this message in a reply
Post Reply 




User(s) browsing this thread: 3 Guest(s)