REAL_TO_FRAC - Algorithmus in eine Dezimalzahl in einen Bruch umzuwandeln

Begonnen von cleber.ruiz, 19. November 2010, 03:22:08

Vorheriges Thema - Nächstes Thema

0 Mitglieder und 1 Gast betrachten dieses Thema.

cleber.ruiz

Hello community OSCAT.

I found a algorithm at http://homepage.smc.edu/kennedy_john/DEC2FRAC.PDF which can be used to convert any decimal number in a fraction.
I needed this solution, because I use MOVIDRIVE from SEW-EURODRIVE to control aplications such as Flying Saw to cut materials during synchronized moviment.
The problem is that the ratio between master and slave must be adjusted in two variables or parameters of Movidrive named GFMaster and GFSlave which works as a fraction.
With this algorithm I rewrote a function block below that cam be used for this purpose.
I made some tests with it running in MoviPLC model DEH41B from SEW and worked very well. 
I would be grateful if this function can be added in the next revision of the library Oscat.lib

FUNCTION_BLOCK REAL_TO_FRAC
VAR_INPUT
   Decimal: REAL;
   AccuracyFactor: REAL := 5.E-007;
END_VAR
VAR_OUTPUT
   Numerator: DINT;
   Denominator: DINT;
END_VAR
VAR
   DecimalSign : REAL;
   Z : REAL;
   PreviousDenominator : REAL;
   ScratchValue : REAL;

   FractionNumerator: REAL;
   FractionDenominator: REAL;
END_VAR

IF Decimal < 0.0 THEN
   DecimalSign := -1.0;
   ELSE DecimalSign := 1.0;
END_IF

Decimal := ABS (Decimal);
IF Decimal=D_TRUNC(Decimal) THEN (*handles exact integers including 0*)
   FractionNumerator := Decimal*DecimalSign;
   FractionDenominator := 1.0;
   RETURN; (*EXIT;*)
END_IF;

IF (Decimal < 1.0E-19) THEN (*X = 0 already taken care of *)
   FractionNumerator := DecimalSign;
   FractionDenominator := 9999999999999999999.0;
   RETURN;
END_IF;

IF (Decimal > 1.0E19) THEN
   FractionNumerator := 9999999999999999999.0*DecimalSign;
   FractionDenominator := 1.0;
   RETURN;
END_IF;

Z := Decimal;
PreviousDenominator := 0.0;
FractionDenominator := 1.0;
REPEAT
   Z := 1.0 / ( Z - D_TRUNC( Z ) );
   ScratchValue := FractionDenominator;
   FractionDenominator := FractionDenominator*D_TRUNC(Z)+PreviousDenominator;
   PreviousDenominator := ScratchValue;
   FractionNumerator :=D_TRUNC(Decimal*FractionDenominator + 0.5); (* Rounding Function *)
UNTIL (ABS((Decimal-(FractionNumerator/FractionDenominator))) < AccuracyFactor) OR (Z = D_TRUNC(Z))
END_REPEAT;
FractionNumerator := DecimalSign*FractionNumerator;

(*These last lines where used only to convert the output variables in double integer*)
Numerator := REAL_TO_DINT(FractionNumerator);
Denominator:= REAL_TO_DINT(FractionDenominator);

peewit

ZitatI would be grateful if this function can be added in the next revision of the library Oscat.lib

thank you, that we do

cleber.ruiz

#2
Correction:
I made a mistake when I wrote the last lines in this code.

   (*These last lines where used only to convert the output variables in double integer*)
   Numerator := REAL_TO_DINT(FractionNumerator);
   Denominator:= REAL_TO_DINT(FractionDenominator);

To this function block be able to calculate fractions of integers numbers including the zero. Is also necessary to put that last lines in other parts of the code.
Following, you can have the revised code and also download the export file of it.

Sorry for my falure.

FUNCTION_BLOCK REAL_TO_FRAC
VAR_INPUT
   Decimal: REAL;
   AccuracyFactor: REAL := 5.E-007;
END_VAR
VAR_OUTPUT
   Numerator: DINT;
   Denominator: DINT;
END_VAR
VAR
   DecimalSign : REAL;
   Z : REAL;
   PreviousDenominator : REAL;
   ScratchValue : REAL;

   FractionNumerator: REAL;
   FractionDenominator: REAL;
END_VAR

IF Decimal=D_TRUNC(Decimal) THEN (*handles exact integers including 0*)
   FractionNumerator := Decimal*DecimalSign;
   FractionDenominator := 1.0;

   (*These last lines where used only to convert the output variables in double integer*)
   Numerator := REAL_TO_DINT(FractionNumerator);
   Denominator:= REAL_TO_DINT(FractionDenominator);
   RETURN;
END_IF;

IF (Decimal < 1.0E-19) THEN (*X = 0 already taken care of *)
   FractionNumerator := DecimalSign;
   FractionDenominator := 9999999999999999999.0;

   (*These last lines where used only to convert the output variables in double integer*)
   Numerator := REAL_TO_DINT(FractionNumerator);
   Denominator:= REAL_TO_DINT(FractionDenominator);
   RETURN;
END_IF;

IF (Decimal > 1.0E19) THEN
   FractionNumerator := 9999999999999999999.0*DecimalSign;
   FractionDenominator := 1.0;

   (*These last lines where used only to convert the output variables in double integer*)
   Numerator := REAL_TO_DINT(FractionNumerator);
   Denominator:= REAL_TO_DINT(FractionDenominator);
   RETURN;
END_IF;

Z := Decimal;
PreviousDenominator := 0.0;
FractionDenominator := 1.0;
REPEAT
   Z := 1.0 / ( Z - D_TRUNC( Z ) );
   ScratchValue := FractionDenominator;
   FractionDenominator := FractionDenominator*D_TRUNC(Z)+PreviousDenominator;
   PreviousDenominator := ScratchValue;
   FractionNumerator :=D_TRUNC(Decimal*FractionDenominator + 0.5); (* Rounding Function *)
UNTIL (ABS((Decimal-(FractionNumerator/FractionDenominator))) < AccuracyFactor) OR (Z = D_TRUNC(Z))
END_REPEAT;
FractionNumerator := DecimalSign*FractionNumerator;

(*These last lines where used only to convert the output variables in double integer*)
Numerator := REAL_TO_DINT(FractionNumerator);
Denominator:= REAL_TO_DINT(FractionDenominator);

[gelöscht durch Administrator]