## Rounding numbers

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
neil
Posts: 594
Joined: Mar 17, 2022 23:26

### Re: Rounding numbers

Hi hhr I got this from deepai.

Code: Select all

#include once "crt/math.bi"

Dim num As Double
Dim roundedNum As Integer

Input "Enter a number to round: ", num

roundedNum = Round(num)

Print "The rounded number is: "; roundedNum

sleep
Last edited by neil on Feb 05, 2024 0:29, edited 1 time in total.
hhr
Posts: 216
Joined: Nov 29, 2019 10:41

### Re: Rounding numbers

Hi neil,
there is an instruction that one doesn't know (round). We definitely have to tell the FreeBASIC developers about this.
neil
Posts: 594
Joined: Mar 17, 2022 23:26

### Re: Rounding numbers

Maybe this is better?
#include once "crt/math.bi"
hhr
Posts: 216
Joined: Nov 29, 2019 10:41

### Re: Rounding numbers

Yes very good. We shouldn't put too much strain on the developers.
neil
Posts: 594
Joined: Mar 17, 2022 23:26

### Re: Rounding numbers

Hi hhr Here's another way to round numbers.

Code: Select all

Dim number As Single
Dim integerPart As Integer
Dim decimalPart As Single

Input "Enter a Number: ", number

integerPart = Int(number)
decimalPart = number - integerPart

If decimalPart >= 0.5 Then
integerPart = integerPart + 1
End If

Print "Rounded number: "; integerPart

sleep
neil
Posts: 594
Joined: Mar 17, 2022 23:26

### Re: Rounding numbers

Here's PI to 2 decimal places.

Code: Select all

Function RoundNumber(number As Double, decimalPlaces As Integer) As Double
Dim multiplier As Double
multiplier = 10 ^ decimalPlaces
RoundNumber = Int(number * multiplier + 0.5) / multiplier
End Function

Dim num As Double
Dim roundedNum As Double
Dim decimalPlaces As Integer

num = 3.14159
decimalPlaces = 2

roundedNum = RoundNumber(num, decimalPlaces)
Print "Original number: "; num
Print "Rounded number: "; roundedNum
sleep
neil
Posts: 594
Joined: Mar 17, 2022 23:26

### Re: Rounding numbers

Here's another example. This prints PI to 5 decimal places.

Code: Select all

Function RoundDecimal(num As Double, decimals As Integer) As Double
Dim temp As Double
temp = 10 ^ decimals
RoundDecimal = Int(num * temp + 0.5) / temp
End Function

Dim number As Double
number = 3.14159265
Print RoundDecimal(number, 5)  ' 5 decimal places
sleep
hhr
Posts: 216
Joined: Nov 29, 2019 10:41

### Re: Rounding numbers

A counter-example takes us back to the beginning.

You cannot use double because double works internally with a binary representation.
Errors occur when converting from decimal to binary and vice versa.

That's why I think you have to work consistently with strings and/or Ulongint.

Perhaps you have another idea.

Code: Select all

Function RoundNumber(number As Double, decimalPlaces As Integer) As Double
Dim multiplier As Double
multiplier = 10 ^ decimalPlaces
RoundNumber = Int(number * multiplier + 0.5) / multiplier
End Function

Dim num As Double
Dim roundedNum As Double
Dim decimalPlaces As Integer
'=======================================
num = 95.225000195
decimalPlaces = 4

roundedNum = RoundNumber(num, decimalPlaces)
Print "Original number: "; num,decimalPlaces
Print "Rounded number:  "; roundedNum
print string(35,"-")
'=======================================
num = 836.87938866205
decimalPlaces = 5

roundedNum = RoundNumber(num, decimalPlaces)
Print "Original number: "; num,decimalPlaces
Print "Rounded number:  "; roundedNum
print string(35,"-")
'=======================================
num = 0.087898873956
decimalPlaces = 4

roundedNum = RoundNumber(num, decimalPlaces)
Print "Original number: "; num,decimalPlaces
Print "Rounded number:  "; roundedNum
print string(35,"-")
'=======================================
sleep
neil
Posts: 594
Joined: Mar 17, 2022 23:26

### Re: Rounding numbers

Hi hhr I only tested it with PI. Have you looked into the Round function?
hhr
Posts: 216
Joined: Nov 29, 2019 10:41

### Re: Rounding numbers

With the Round function, one cannot specify the decimal places.

I have also noticed that all these functions have errors.

The Format function has the worst error.

As I said, I can only avoid the errors if I avoid Double.

The functions I introduced here at the beginning (RoundDouble, RoundDouble3) work with Strings and/or Ulongint.
They are not complete, there is still a lot to do, but they work without errors.

I am interested to know if anyone has any other ideas.
neil
Posts: 594
Joined: Mar 17, 2022 23:26

### Re: Rounding numbers

Hi hhr look at this.

Code: Select all

#include "crt/stdio.bi"
Dim AS Double num
num = 95.225000195

printf(!"original number %.9f\n\n",num)
printf(!"round to 1 place %.1f\n",num)
printf(!"round to 2 places %.2f\n",num)
printf(!"round to 3 places %.3f\n",num)
printf(!"round to 4 places %.4f\n",num)
printf(!"round to 5 places %.5f\n",num)
printf(!"round to 6 places %.6f\n",num)
printf(!"round to 7 places %.7f\n",num)
printf(!"round to 8 places %.8f\n",num)
printf(!"round to 9 places %.9f\n",num)

sleep
hhr
Posts: 216
Joined: Nov 29, 2019 10:41

### Re: Rounding numbers

Here is an example where printf and sprintf make an error.
But you have to test with as many examples as possible, which is only possible with a program.

Code: Select all

#Include "crt.bi" ' is needed for sprintf,printf

Dim As Double n
Dim As Integer decimals
Dim As Zstring*20 zs

n = 462.445
decimals = 2

Print "Number:     ";n

Print "printf:      ";
printf("%.*f",decimals,n)
Print

sprintf(zs,"%.*f",decimals,n)
Print "sprintf:     ";zs

Print "Print Using: ";
Print Using "###.##";n

Sleep
hhr
Posts: 216
Joined: Nov 29, 2019 10:41

### Re: Rounding numbers

With this example I am trying to test printf.
I hope that the numbers used for testing are put together reasonably.

Code: Select all

#Include "crt.bi"

Function printfToString(number As Double, decimals As Integer) As String
Dim As Long i,row,column
Dim As String s,exponent
s = Str(number) 'Copy the number as string

If Instr(s,"e") Then 'Separate mantissa and exponent
exponent = Right(s,Len(s)-Instr(s,"e")+1)
s = Rtrim(s,exponent)
End If

'Save row and column, write to console:
column = Pos
row = Csrlin
printf("%.*f",decimals,number)
s = Space(0)
For i = 0 To 20
s += Chr(Screen(row,column+i))
Next
'Delete written text in console:
Locate row,column
Print Space(20); 'Note the semicolon
'Set the cursor to original position:
Locate row,column
'Finalize string:
s = Rtrim(s)
If Instr(s,".") > 0 Then s = Rtrim(s,"0")
s = Rtrim(s,".")

s = s & exponent
'A positive number should be preceded by a space:
If (Left(s,1) <> "-") Then s = Space(1) & s

Return s
End Function

Function RoundDouble(number As Double, decimals As Integer) As String
Dim As String s,sign,exponent
Dim As Integer dp
Dim As Byte i,carry

s = Str(number) 'Copy the number as string

If Left(s,1) = "-" Then 'Remove the sign
sign = "-"
s = Ltrim(s,"-")
Else
sign = Space(1)
End If

If Instr(s,"e") Then 'Separate mantissa and exponent
exponent = Right(s,Len(s)-Instr(s,"e")+1)
s = Rtrim(s,exponent)
End If

dp = Instr(s,".") 'decimal point

If dp > 0 Then 'If decimal point present

i = dp + Abs(decimals) 'Determine the first carry
If s[i] >= 53 Then carry = 1 'Chr(53)="5"
s = Left(s,i) ' Remove omitted digits

While (carry = 1)
i -= 1
If i = -1 Then s = "1" & s : Exit While 'The carry has run through all the digits, can happen with many nines.
If Chr(s[i]) = "." Then i -= 1 'Skip the decimal point
If s[i] < 57 Then 'Chr(57)="9"
s[i] += 1
carry = 0
Else
s[i] = 48 'Chr(48)="0", Carry over remains 1
End If
Wend

s = Rtrim(s,"0")
s = Rtrim(s,".")
End If

s = sign & s & exponent

Return s
End Function

'testing:
Randomize
Dim As Double n,nsign
Dim As Integer decimals
Dim As String s1,s2
Do
'Make up the number:
n = Fix(Rnd*1000000)/1000
nsign = Iif(Rnd<0.5,-1,1)
n = nsign*n
decimals = Int(Rnd*4)
'Printout:
s1 = RoundDouble(n,decimals)
s2 = printfToString(n,decimals)
Print "Number: ";Space(8);n;Tab(50);"decimals: ";decimals
Print "RoundDouble:    ";s1
Print "printfToString: ";s2
If s1<>s2 Then Print "Different, any key to continue...":Sleep
Print String(30,"-")
'Getkey
Loop
neil
Posts: 594
Joined: Mar 17, 2022 23:26

### Re: Rounding numbers

Hi hhr Try testing this.

Code: Select all

Dim a as double
a = 836.87938866205

Print "original number ";a
PRINT USING "###.#"; a
PRINT USING "###.##"; a
PRINT USING "###.###"; a
PRINT USING "###.####"; a
PRINT USING "###.#####"; a
PRINT USING "###.######"; a
PRINT USING "###.#######"; a
PRINT USING "###.########"; a
PRINT USING "###.#########"; a
PRINT USING "###.##########"; a
PRINT USING "###.###########"; a

sleep
caseih
Posts: 2159
Joined: Feb 26, 2007 5:32

### Re: Rounding numbers

I just read a trick for rounding numbers with printf. The trick is to add a 5 to the number, in the decimal place just past the digits you want to round to. For example, printf("%0.2f", 0.635 + 0.005). that guarantees it will round even as it truncates.