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

Post by neil »

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: 211
Joined: Nov 29, 2019 10:41

Re: Rounding numbers

Post by hhr »

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

Post by neil »

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

Re: Rounding numbers

Post by hhr »

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

Post by neil »

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

Post by neil »

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

Post by neil »

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: 211
Joined: Nov 29, 2019 10:41

Re: Rounding numbers

Post by hhr »

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

Post by neil »

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

Re: Rounding numbers

Post by hhr »

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

Post by neil »

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: 211
Joined: Nov 29, 2019 10:41

Re: Rounding numbers

Post by hhr »

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: 211
Joined: Nov 29, 2019 10:41

Re: Rounding numbers

Post by hhr »

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)
   'Read from console:
   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

Post by neil »

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: 2157
Joined: Feb 26, 2007 5:32

Re: Rounding numbers

Post by caseih »

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.
Post Reply