Return the Fractional part of a number

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

Return the Fractional part of a number

Post by Rainwulf »

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:

Post by RayBritton »

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
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Post by fxm »

You can use this formula which runs for positive or negative values :
fractional = number - Sgn(number) * Int(Sgn(number) * number)
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Post by counting_pine »

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: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

mymod

Post by owen »

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 Double

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(n Mod m)+"."+Mid(Str(n),Instr(Str(n),".")+1))
	Else
		mymod = (n Mod m)
	EndIf
	End Select
End Function

Dim As Double n
Dim As Integer m
n=365.01
m=360
Print n;" Mod";m;" ="; n Mod m
Print n;" Mod";m;" ="; n Mod m + Frac(n)
Print n;" Mod";m;" ="; mymod(n,m)
Sleep
End

' 365.01 Mod 360 = 5
' 365.01 Mod 360 = 5.009999999999991
' 365.01 Mod 360 = 5.01
 
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

oops forgot about mod rounding

Post by owen »

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 Select
End Function

counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: mymod

Post by counting_pine »

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 string
for i = 0 to 100
    s = "1e-" & i
    print s, val(s)
next
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

using variable as double

Post by owen »

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,result
Dim As Integer m
m=360
For n = 365.0 To 365.9 Step .1
	result = n Mod m + Frac(n)
	Print result
Next
Sleep
End
the results range from 5.0 to 6.8
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Post by counting_pine »

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 string
for 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 string
for i = 0 to 999
    s = str(i / 10#)
    if instr(s & ".", ".") + 1 < len(s) then print s
next
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.
Post Reply