Round a number function problem

General FreeBASIC programming questions.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Round a number function problem

Post by BasicCoder2 »

Are there any math brains here that can show me a simple way to round a single (or double) float value to a rounded value like this using FreeBASIC?

declare function ROUND(f as float) r as integer

input output
SINGLE ROUNDED
-3.0 -3
-2.7 -3
-2.4 -2
-2.1 -2
-1.8 -2
-1.5 -2
-1.2 -1
-0.9 -1
-0.6 -1
-0.3 0
0.0 0
+0.3 0
+0.6 +1
+0.9 +1
+1.2 +1
+1.5 +2
+1.8 +2
+2.1 +2
+2.4 +2
+2.7 +3
+3.0 +3
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Round a number function problem

Post by fxm »

Simply CINT !
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Round a number function problem

Post by BasicCoder2 »

Almost. I notice that 1.5 becomes 1 but -1.5 becomes -2 in the code example below.
So the round up/down rule for .5 isn't symmetrical between positive and negative number in this program.

Code: Select all

screenres 640,480,32
dim as single ii
for i as single = -3 to 3 step 0.3
    print i;tab(20);CInt(i)
    print "----------------------------------------------"
next i

sleep
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Re: Round a number function problem

Post by MichaelW »

I would have guessed that CINT uses the CRT, but apparently not.

Code: Select all

#include "crt.bi"

dim as single a1(0 to 20) = {-3.0,-2.7,-2.4,-2.1,-1.8,-1.5,-1.2,-0.9,-0.6, _
                             -0.3, 0.0,+0.3,+0.6,+0.9,+1.2,+1.5,+1.8,+2.1, _
                             +2.4,+2.7,+3.0 }
                             
dim as double a2(0 to 20) = {-3.0,-2.7,-2.4,-2.1,-1.8,-1.5,-1.2,-0.9,-0.6, _
                             -0.3, 0.0,+0.3,+0.6,+0.9,+1.2,+1.5,+1.8,+2.1, _
                             +2.4,+2.7,+3.0 }  
                             
for i as integer = 0 to 20
    print a1(i);chr(9);rintf(a1(i));chr(9);rint(a2(i))
next

sleep

Code: Select all

-3      -3      -3
-2.7    -3      -3
-2.4    -2      -2
-2.1    -2      -2
-1.8    -2      -2
-1.5    -2      -2
-1.2    -1      -1
-0.9    -1      -1
-0.6    -1      -1
-0.3    -0      -0
 0       0       0
 0.3     0       0
 0.6     1       1
 0.9     1       1
 1.2     1       1
 1.5     2       2
 1.8     2       2
 2.1     2       2
 2.4     2       2
 2.7     3       3
 3       3       3
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Round a number function problem

Post by fxm »

Same result with the FB keyword CINT:

Code: Select all

#include "crt.bi"

dim as single a1(0 to 20) = {-3.0,-2.7,-2.4,-2.1,-1.8,-1.5,-1.2,-0.9,-0.6, _
                             -0.3, 0.0,+0.3,+0.6,+0.9,+1.2,+1.5,+1.8,+2.1, _
                             +2.4,+2.7,+3.0 }
                             
dim as double a2(0 to 20) = {-3.0,-2.7,-2.4,-2.1,-1.8,-1.5,-1.2,-0.9,-0.6, _
                             -0.3, 0.0,+0.3,+0.6,+0.9,+1.2,+1.5,+1.8,+2.1, _
                             +2.4,+2.7,+3.0 }  
                             
for i as integer = 0 to 20
    print a1(i);chr(9);rintf(a1(i));chr(9);rint(a2(i));chr(9);cint(a1(i));chr(9);cint(a2(i))
next

sleep
In fact the rounding depends on program context!
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Re: Round a number function problem

Post by MichaelW »

fxm wrote:Same result with the FB keyword CINT
...
In fact the rounding depends on program context!
Yes, that is the result I get, but why would the result vary with the context?
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Round a number function problem

Post by fxm »

Depending on program calculation context!

The BasicCoder2's code, but just with 'step=0.5':

Code: Select all

screenres 640,480,32

for i as single = -3 to 3 step 0.5
    print i;tab(20);CInt(i)
    print "----------------------------------------------"
next i

sleep
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Round a number function problem

Post by badidea »

Remove sign, then add sign again, something like this?

Code: Select all

dim as single a
dim as integer i, j

for i = -10 to +10
	a = i * 0.3
	j = int(abs(a)+0.5)*sgn(a)
	print a, j
next
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Round a number function problem

Post by D.J.Peters »

In case of SINGLE you can cast it as ULONG and clear the sign before call INT().
In case of DOUBLE you can cast it as ULONGINT and clear the sign before call INT().

here are:
function SNGRound(x as single) as integer
function DBLRound(x as double) as longint


Joshy

Code: Select all

union U_SNG
  as single s
  as ulong  u
end union

function SNGRound(x as single) as integer
  dim as U_SNG u=any
  u.s = x + .5
  dim as ulong s = u.u and &H80000000
  if s then  
    u.u = u.u and &H7FFFFFFF
    u.u = int(u.s)
    return &HFFFFFFFF - u.u
  else
    return int(u.s)
  end if
end function

union U_DBL
  as double   d
  as ulongint u
end union

function DBLRound(x as double) as longint
  dim as U_DBL u=any
  u.d = x + .5
  dim as ulongint s = u.u and &H8000000000000000
  if s then  
    u.u = u.u and &H7FFFFFFFFFFFFFFF
    u.u = int(u.d)
    return &HFFFFFFFFFFFFFFFF - u.u
  else
    return int(u.d)
  end if
end function

dim as single  si
dim as double  di
dim as integer j
dim as longint k

for si = -3 to +3 step .25
  di=si
  j = SNGRound(si)
  k = DBLRound(di)
  print si,j,k
next
sleep
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Round a number function problem

Post by MrSwiss »

Simpler version (no unions):

Code: Select all

Function SNGRound (ByVal s As Single) As Long
	Dim As Long ti
	If s < 0.0 Then
		s  -= .000001		' add/subtract bias
		s  *= -1			' switch sign
		ti  = CLng(s)		' convert
		ti *= -1			' switch sign
		Return ti
	Else
		s  += .000001		' add/subtract bias
		Return CLng(s)		' convert
	EndIf
End Function

Function DBLRound (ByVal d As Double) As LongInt
	Dim As LongInt ti
	If d < 0.0 Then
		d  -= .0000000001	' add/subtract bias
		d  *= -1			' switch sign
		ti  = CLngInt(d)	' convert
		ti *= -1			' switch sign
		Return ti
	Else
		d  += .0000000001	' add/subtract bias
		Return CLngInt(d)	' convert
	EndIf
End Function


dim as single  si
dim as double  di
dim as Long j
'Dim as Integer j
dim as longint k

for si = -3 to +3 step .25
  di=si
  j = SNGRound(si)
  k = DBLRound(di)
  print si,,j,,k
next
sleep
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Round a number function problem

Post by BasicCoder2 »

So much to digest! Thank you for all your inputs.
The difference between Single and Double surprised me as well.
Whereas the Single returns 3 the Double returned 2.999999999999999

Code: Select all

screenres 640,480,32
locate 1,1
for i as single = -3.0 to 3.0 step 0.3
    print i;tab(25);CInt(i)
    print "----------------------------------------------"
next i
sleep
cls
locate 1,1
for i as double = -3.0 to 3.0 step 0.3
    print i;tab(25);CInt(i)
    print "----------------------------------------------"
next i
while inkey<>"":wend
while inkey="":wend
.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Round a number function problem

Post by D.J.Peters »

MrSwiss wrote:Simpler version (no unions):
@MrSwiss "Simpler" does not mean better
your code used multiplication :-(
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Round a number function problem

Post by BasicCoder2 »

badidea wrote:Remove sign, then add sign again, something like this?
I had the same thoughts and the way you did it seems to work but I wanted it as a function.
Something like this although this one looks to me like yours it doesn't work properly.

Code: Select all

screenres 640,480,32

function round(n as single) as integer
    return int(abs(n)+0.5)*sgn(n)
end function

for i as single = -3 to 3 step 0.3
    print i,round(i)
    print "--------------------------------"
next i

sleep
.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Round a number function problem

Post by BasicCoder2 »

Just to clarify the problem the context is wanting to plot a reflection of pixels around some center point.
The data is in the form of floats but a pixel has an integer value but negative and positive floats are round down instead of away from the center point. Apparently there are four ways of rounding numbers and the dividing point 0.5 can be chosen either up or down but I would at least want it to be consistent for positive and negative numbers.

Code: Select all

screenres 640,480,32
color rgb(0,0,0),rgb(255,255,255):cls

for i as single = -100.0 to 100.0 step 2.3
    if i<0 then color rgb(255,0,0)
    if i>0 then color rgb(0,0,255)
    pset (i+320,240)
    line (320,0)-(320,238),rgb(0,255,0)
    line (320,242)-(320,479),rgb(0,255,0)
next i

sleep
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Round a number function problem

Post by badidea »

Whereas the Single returns 3 the Double returned 2.999999999999999
I expect that exactly 3 does not exist for single and double floats. the difference between 3 and 2.999999999999999 is maybe a print formatting issue.
Post Reply