## Return the Fractional part of a number

General FreeBASIC programming questions.
Rainwulf
Posts: 35
Joined: Mar 28, 2007 11:33

### Return the Fractional part of a number

I need the opposite of int...

I need to get the fraction part of a number, like everything after the decimal point.

For example.
Given 5.123

It returns ".123"

Is there a function that does that already? I am looking in the help file.

I hacked a function together that uses mod, but its not the best.

fractional=((number*1000) MOD 1000)/1000

As well, floor and ceiling would be great as well.
RayBritton
Posts: 306
Joined: Jun 02, 2005 7:11
Contact:
FRAC does that.

Code: Select all

`print frac(5.123)`

displays 0.123

http://www.freebasic.net/wiki/wikka.php?wakka=KeyPgFrac

For the other functions:

Code: Select all

`Int(i)`

where i is between 0 and 0.999 inclusive, returns the floor and add 1 to get the ceiling.

http://www.freebasic.net/wiki/wikka.php?wakka=KeyPgInt
Last edited by RayBritton on Sep 17, 2009 13:07, edited 3 times in total.
fxm
Posts: 9916
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE
You can use this formula which runs for positive or negative values :
fractional = number - Sgn(number) * Int(Sgn(number) * number)
counting_pine
Posts: 6225
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs
It should be noted that frac() is the counterpart of fix() - i.e. frac(x) = x - fix(x). Because fix() truncates rather than rounds down, this results in non-positive results for negative numbers.

If you want the result always to be non-negative, you should explicitly do "x - int(x)" instead. (int() always rounds down, so obviously the difference can never be negative.)

To get the ceiling, you should do "-int(-x)". Don't just add 1 to int() because that will mean whole numbers get rounded up - e.g. int(3) + 1 = 4.
owen
Posts: 554
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

### mymod

n mod m : the result is an integer
n mod m + frac(n): using FRAC returns an incorrect result
mymod(n,m): seems to work correctly

365.01 Mod 360 = 5
365.01 Mod 360 = 5.009999999999991
365.01 Mod 360 = 5.01

Code: Select all

`'\$lang: "deprecated"Declare Function mymod(n As Double,m As Integer) As DoubleFunction mymod(n As Double,m As Integer) As Double   Select Case n      Case 0   mymod = 0      Case Else   If Instr(Str(n),".")<>0 Then      mymod=Val(Str(n Mod m)+"."+Mid(Str(n),Instr(Str(n),".")+1))   Else      mymod = (n Mod m)   EndIf   End SelectEnd FunctionDim As Double nDim As Integer mn=365.01m=360Print n;" Mod";m;" ="; n Mod mPrint n;" Mod";m;" ="; n Mod m + Frac(n)Print n;" Mod";m;" ="; mymod(n,m)SleepEnd' 365.01 Mod 360 = 5' 365.01 Mod 360 = 5.009999999999991' 365.01 Mod 360 = 5.01 `
owen
Posts: 554
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

### oops forgot about mod rounding

298.7967216637024 mod 360 is 299 because 298.7xx is rounded up
so naturally mymod function (above post) didn't work.

this is better

Code: Select all

`Function mymod(n As Double,m As Integer) As Double   Select Case n      Case 0         mymod = 0      Case Else         If InStr(Str(n),".")<>0 Then            mymod=Val(Str(val(Mid(Str(n),1,InStr(Str(n),".")-1)) Mod m)+"."+Mid(Str(n),InStr(Str(n),".")+1))         Else            mymod = (n Mod m)         EndIf   End SelectEnd Function`
counting_pine
Posts: 6225
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

### Re: mymod

owen wrote:n mod m : the result is an integer
n mod m + frac(n): using FRAC returns an incorrect result
That's as correct as floating-point can get.
Powers of 1/10 cannot be stored accurately in binary, just as powers of 1/3 cant be stored in decimal. For example:

1/300 is 0.0033333 in decimal with 5 digits precision.
1 + 1/300 is 1.0033 in the same format.
If you take 1 away from that you get 0.0033000.

So it looks like the math was wrong, but the math was actually accurate. It's just that it was working on a number that wasn't exactly what you want it to be.

In your trick, str() is giving you the imprecise number .009999..., but to fewer places (because the part before the decimal point takes up more of the significant digits), so it looks accurate. When you pass it back to val(), it fudges the end digits so the final decimal looks as close as it can to .01.

Usually the binary digits can be fudged enough with val() so that the decimal expansion looks like the decimal number you want, but it's not always guaranteed, e.g.

Code: Select all

`dim i as integer, s as stringfor i = 0 to 100    s = "1e-" & i    print s, val(s)next`
owen
Posts: 554
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

### using variable as double

thanx for the post
if my goal is to get a result of 5.0 to 5.9 into the variable called result what's my best choice?

Code: Select all

`Dim As Double n,resultDim As Integer mm=360For n = 365.0 To 365.9 Step .1   result = n Mod m + Frac(n)   Print resultNextSleepEnd`

the results range from 5.0 to 6.8
counting_pine
Posts: 6225
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs
One solution might be to use integer math and store everything as tenths of degrees. So a full circle would be 3600.
To ensure it prints correctly without using Print Using or Format you'll probably want to use Str() on the integer and manually insert the decimal point.

Code: Select all

`dim i as integer, s as stringfor i = 0 to 99        s = str(i)    s = left(s, len(i)-1) & "." & right(s, 1)    if left(s, 1) = "." then s = "0" & s        print s    next`

I've just checked, and Print simply won't print some double precision values the way you'd want it to, so you can't just print the result of the number divided by 10:

Code: Select all

`dim i as integer, s as stringfor i = 0 to 999    s = str(i / 10#)    if instr(s & ".", ".") + 1 < len(s) then print snext`
Early weak points seem to be values over 8 and values over 64, which last until the number gains an extra decimal digit and the loss of precision falls off the end.