LB Booster
Programming >> Liberty BASIC language >> FRACTIONS
http://lbb.conforums.com/index.cgi?board=lblang&action=display&num=1487851015

FRACTIONS
Post by Optimax on Feb 23rd, 2017, 10:56am

I wondered how some codes could give a result like 2/3 instead of 0.666666...
So I tried to produce the same display.
I've had much difficulties with decimals numbers.
Hoping that everything now works ...

Code:

'FRACTIONS.BAS      LBB     23-02-2017
'==============

' returns the result of a division  (a / b)   as a fraction , rather then as a decimal number
' this means:  < 2/3 >  rather then  < 0.66666... >
' both terms of a fraction are divided by the GCD (Greatest Common Divisor)
' results display:      < x = a / b >  as a decimal,     and  < x$ >  as a   "fraction to text"
' only 2 procedures: < SUB FRACTION  a, b > , which calls  < FUNCTION GCD (a, b) >

' examples, 10 couples of numbers loaded and divided by the main code
DATA 10
DATA 5, 0, 0, 0, 0, 6, 3, 6, -8, 6, 12, -8, -10, -24, 0.375, -0.500, 0.16, 0.08, -1.2, 0.8

[Main]

READ n
FOR i = 1 TO n
    CLS
    READ a,  b
    PRINT "a = "a, "b = "; b, "x = a / b"
    !PRINT''
    CALL FRACTION  a, b
    !PRINT''
    INPUT "Type <ENTER / RETURN > to continue..."; enter$
NEXT i

!* QUIT

[Procedures]

SUB FRACTION a, b

' *** special cases a/0 or 0/0 or 0/b

IF (a <> 0) AND (b = 0) THEN PRINT, "division by zero, no result": EXIT SUB
IF (a = 0) AND (b = 0) THEN PRINT, "dividing zero by zero , undetermination, no result": EXIT SUB
IF (a = 0) AND (b <> 0)  THEN x = 0: x$ = "0"

' *** common case, no zero's

x = a / b 

    IF x = INT(x) THEN x$ = STR$(x)      ' if   x = a/b   is an integer
                     
    IF x <> INT(x) THEN                           ' if   x = a/b  has decimals
           a = ABS(a): b = ABS(b)              ' positive numbers only
            k = GCD (a, b)
            a = a/k
            b = b/k
            x$ = STR$(a)  + "/" + STR$(b)
            IF x < 0 THEN x$ = "-" + x$        ' restoring minus sign if needed
    END IF   

' *** display results
    
           PRINT,, "x  = "; x
           PRINT
           PRINT,, "x$ = "; x$
               
END SUB

FUNCTION GCD (M, N)

' GCD    Greatest Common Divisor
' M and N receive the absolute values of  'a'  and  'b', but also decimals

	IF M = 0 OR N = 0 THEN EXIT FUNCTION
	! IF M < N THEN SWAP M, N

' case decimals, make them integer and hope everything works
' N is the lower of N, M

     factor = 1
     
     WHILE N < 1
        M = M*10
        N = N*10
        factor = factor * 10
     WEND

' now classical Euclides' algorithm

	DO
	R = M MOD N
		IF R = 0 THEN EXIT DO
		M = N
		N = R
              END IF
	LOOP

      IF N < 1 THEN N = 1             ' who knows what could happen else ...
      GCD = N / factor                   ' if no decimals, factor = 1 
      
END FUNCTION
 

Re: FRACTIONS
Post by Jack Kelly on Feb 24th, 2017, 07:41am

Bonjour, Optimax.

Your fractions program looks good to me. Your BASIC skills are impressive. But why do decimals give you difficulties?

Regards,
Jack
Re: FRACTIONS
Post by Optimax on Feb 24th, 2017, 07:57am

Bien le bonjour,

Thanks for your interest in my short code.
The difficulties with decimals could well be in the GCD (PGCD) algorithm, which is best suited for integers. So we make decimals as integers by mutiplying them by a multiple of 10 (the factor), and now it works better. A warning "number too big " could still overcome occur.

Regards


Re: FRACTIONS
Post by Richard Russell on Feb 24th, 2017, 4:43pm

on Feb 24th, 2017, 07:41am, Jack Kelly wrote:
But why do decimals give you difficulties?

I expect it's the old problem of decimal values not always being precisely representable in binary floating-point format. The classic example is the value 0.1 which can obviously be represented precisely as a decimal number but not as a binary number.

The closest that LBB can get to 0.1 is this value (expressed as a decimal):

Code:
0.1000000000000000000013552527156068805425093160010874271392822265625 

For sure it's very close to 0.1 (19 zeros follow before you get to the next non-zero digit) but it's not precisely 0.1.

In this particular case, because of the way rounding works out, multiplying this value by 10 does result in an answer of exactly 1. But you won't always be so lucky, for example take the value 0.001. The closest internal representation to this is:

Code:
0.00100000000000000000006437450399132682576919251005165278911590576171875 

Multiplying this by 1000 doesn't give you the expected integer value; instead you get this:

Code:
1.000000000000000000108420217248550443400745280086994171142578125 

So now a loop like this doesn't do what you might hope it would:

Code:
    x = 0.001
    WHILE x <> INT(x)
        x *= 10
    WEND
    PRINT x 

Richard.

Re: FRACTIONS
Post by tsh73 on Feb 24th, 2017, 7:17pm

I wonder what END IF on line 88 (in GCD function) supposed to do? (I just have other BASIC complaining so it made me wonder.)
Re: FRACTIONS
Post by Optimax on Feb 25th, 2017, 06:27am

That <END IF > has indeed nothing to do there.
But LBB doesn't complain.
It must have forgotten there from previous lines of code.
Sorry for this.


Re: FRACTIONS
Post by SarmedNafi on Feb 26th, 2017, 10:02am

I got this result !
Is it Normal ?

a = 9 b = 6 x = a / b



x = 1.5

x$ = 3/2



Type <ENTER / RETURN > to continue...



Re: FRACTIONS
Post by Richard Russell on Feb 26th, 2017, 10:53am

on Feb 26th, 2017, 10:02am, SarmedNafi wrote:
I got this result ! Is it Normal ?

It seems to be correct. You get the same result by dividing the numerator and denominator by 3.

Richard.

Re: FRACTIONS
Post by SarmedNafi on Feb 27th, 2017, 09:40am

Yes, it is correct,

I expects the result will be in the following format :

X$ = 1 1/2

KASIO Produce calculators give results such that or 1.5 format.
Some times the decimal long fraction is not welcome.
However the code is very interested, thanks to sender.

Regards
Re: FRACTIONS
Post by Optimax on Mar 4th, 2017, 6:29pm

Added a few lines today making fractionary numbers.

This result is displayed as a string and could not be directly converted by VAL nor by EVAL for further calculations.

Regards

Code:
'FRACTIONS.BAS      LBB     04-03-2017
'==============

' returns the result of a division  (a / b)   as a fraction , rather then as a decimal number
' this means:  < 2/3 >  rather then  < 0.66666... >
' both terms of a fraction are divided by the GCD (Greatest Common Divisor)
' results display:      < x = a / b >  as a decimal,     and  < x$ >  as a   "fraction to text"
' only 2 procedures: < SUB FRACTION  a, b > , which calls  < FUNCTION GCD (a, b) >
' xf$ is a fractionnary number like '1 1/4'

' examples, 11 couples of numbers loaded and divided by the main code
DATA 11
DATA 5, 0, 0, 0, 0, 6, 3, 6, -8, 6, 12, -8, -10, -24, 0.375, -0.500, 0.16, 0.08, -1.2, 0.8, 5, 4

[Main]

READ n
FOR i = 1 TO n
    CLS
    READ a,  b
    PRINT "a = "a, "b = "; b, "x = a / b"
    !PRINT''
    CALL FRACTION  a, b
    !PRINT''
    INPUT "Type <ENTER / RETURN > to continue..."; enter$
NEXT i

!* QUIT

[Procedures]

SUB FRACTION a, b

' *** special cases a/0 or 0/0 or 0/b

IF (a <> 0) AND (b = 0) THEN PRINT, "division by zero, no result": EXIT SUB
IF (a = 0) AND (b = 0) THEN PRINT, "dividing zero by zero , undetermination, no result": EXIT SUB
IF (a = 0) AND (b <> 0)  THEN x = 0: x$ = "0"

' *** common case, no zero's

x = a / b 

    IF x = INT(x) THEN x$ = STR$(x)      ' if   x = a/b   is an integer
    IF x <> INT(x) THEN                         ' if   x = a/b  has decimals
            a = ABS(a): b = ABS(b)              ' positive numbers only
            k = GCD (a, b)
            a = a/k
            b = b/k
            x$ = STR$(a)  + "/" + STR$(b)
            IF x < 0 THEN x$ = "-" + x$        ' restoring minus sign if needed
            'added here for displaying a fractionnal result
            xf$ = ""
            IF a > b THEN
            a = a - b
            k = GCD (a, b)
            a = a/k
            b = b/k
            xf$ = STR$(INT(x)) + " " + STR$(a) + "/" + STR$(b)
            END IF
    END IF   
    
' *** display results
    
           PRINT,, "x  = "; x
           PRINT
           PRINT,, "x$ = "; x$
           PRINT
           IF xf$ <> "" THEN PRINT,, "xf$ = "; xf$
               
END SUB

FUNCTION GCD (M, N)

' GCD    Greatest Common Divisor
' M and N receive the absolute values of  'a'  and  'b', even if decimals

	IF M = 0 OR N = 0 THEN EXIT FUNCTION
	! IF M < N THEN SWAP M, N

' case decimals, make them integer and hope everything works
' N is the lower of N, M

     factor = 1
     
     WHILE N < 1
        M = M*10
        N = N*10
        factor = factor * 10
     WEND

' now classical Euclides' algorithm

	DO
	R = M MOD N
		IF R = 0 THEN EXIT DO
		M = N
		N = R
	LOOP

      IF N < 1 THEN N = 1
      GCD = N / factor                   ' if no decimals, factor = 1 
      
END FUNCTION