Round a number function problem

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

Round a number function problem

Postby BasicCoder2 » Nov 14, 2015 8:54

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

Re: Round a number function problem

Postby fxm » Nov 14, 2015 9:22

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

Re: Round a number function problem

Postby BasicCoder2 » Nov 14, 2015 10:12

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

Postby MichaelW » Nov 14, 2015 10:37

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

Re: Round a number function problem

Postby fxm » Nov 14, 2015 10:44

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

Postby MichaelW » Nov 14, 2015 10:51

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

Re: Round a number function problem

Postby fxm » Nov 14, 2015 11:16

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: 2176
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Round a number function problem

Postby badidea » Nov 14, 2015 12:55

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: 8203
Joined: May 28, 2005 3:28
Contact:

Re: Round a number function problem

Postby D.J.Peters » Nov 14, 2015 15:40

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: 3657
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Round a number function problem

Postby MrSwiss » Nov 14, 2015 19:10

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: 3614
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Round a number function problem

Postby BasicCoder2 » Nov 14, 2015 20:27

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: 8203
Joined: May 28, 2005 3:28
Contact:

Re: Round a number function problem

Postby D.J.Peters » Nov 14, 2015 20:50

MrSwiss wrote:Simpler version (no unions):

@MrSwiss "Simpler" does not mean better
your code used multiplication :-(
BasicCoder2
Posts: 3614
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Round a number function problem

Postby BasicCoder2 » Nov 14, 2015 21:20

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: 3614
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Round a number function problem

Postby BasicCoder2 » Nov 14, 2015 22:00

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: 2176
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Round a number function problem

Postby badidea » Nov 15, 2015 12:18

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.

Return to “General”

Who is online

Users browsing this forum: No registered users and 15 guests