## Rounding numbers

### Re: Rounding numbers

@caseih Nice one. You have solved the rounding problem.

### Re: Rounding numbers

@neil

Print Using also works quite well.

However, it makes similar errors as printf and sprintf, although it does not seem to use these functions.
@caseih

I have tried it out. For me, printf then only makes errors.

@neil

We can't get any further with such snapshots.

Print Using also works quite well.

However, it makes similar errors as printf and sprintf, although it does not seem to use these functions.

Code: Select all

```
Dim a As Double
a = 997.935
Print "original number ";a
Print Using "###.##"; a
Print String(20,"-")
a = -643.435
Print "original number ";a
Print Using "####.##"; a
Print String(20,"-")
Sleep
```

I have tried it out. For me, printf then only makes errors.

@neil

We can't get any further with such snapshots.

### Re: Rounding numbers

Here's something to read.

Solutions for floating point rounding errors.

https://softwareengineering.stackexchan ... ing-errors

Solutions for floating point rounding errors.

https://softwareengineering.stackexchan ... ing-errors

### Re: Rounding numbers

The root problem is that although both printf and print using do round, since the numbers are binary floating point the number might be in reality a tiny bit lower than the digit 5. For example you might think the number is 0.635, but it might actually 0.6349999. Adding a 5 in the correct digit does help with that apparently. I'm not sure there are other consequences of doing that.

This works for me:

This works for me:

Code: Select all

```
#include "crt/stdio.bi"
printf(!"%.2f\n",0.634999 + 0.005)
```

Last edited by caseih on Feb 07, 2024 2:17, edited 1 time in total.

### Re: Rounding numbers

This does seem to work OK.

Code: Select all

```
#include "crt/stdio.bi"
printf(!"original number %.6f\n",0.634999)
printf(!"adding to number %.2f\n",0.634999 + 0.005)
sleep
```

### Re: Rounding numbers

You could test for the error. Then only add "0.005" if it's needed.

### Re: Rounding numbers

How do you want to test for errors in a program that outputs many rounded numbers?

Errors occur anyway when calculating with doubles, so small rounding errors are irrelevant.

Errors occur anyway when calculating with doubles, so small rounding errors are irrelevant.

### Re: Rounding numbers

You need to analyze your program in its successive stages for use in the next step of the program.

Then you will find a solution to the rounding errors.

For testing numbers. Here's a rounding number calculator.

https://www.calculatorsoup.com/calculat ... umbers.php

Then you will find a solution to the rounding errors.

For testing numbers. Here's a rounding number calculator.

https://www.calculatorsoup.com/calculat ... umbers.php

### Re: Rounding numbers

What should I say to that?

I would like to have the last word on my topic.

I do not wish any further comments.

EDIT:

I have changed my mind about this.

All comments are welcome.

I would like to have the last word on my topic.

I do not wish any further comments.

EDIT:

I have changed my mind about this.

All comments are welcome.

Last edited by hhr on Feb 14, 2024 18:22, edited 1 time in total.

### Re: Rounding numbers

@hhr I don't think you understood me correctly. You mentioned that rounding errors are common. Therefore, correct the mistakes before moving on to the second section of your program. Put differently, wait till they are corrected before printing them on the screen. I know you will eventually figure out how to do this.

### Re: Rounding numbers

I was thinking of testing the numbers, something like this.

Code: Select all

```
' test if last digit is odd only then add 0.005
Dim AS Double a,b
Dim As string sa,s1
sa = "":s1 = ""
'odd number
a = 997.935
sa = str(a)
s1 = right(sa,1)
b = val(s1)
Print "original number ";a
if (b mod 2) <> 0 Then a += 0.005
Print Using "###.##"; a
Print String(20,"-")
sa = "":s1 = ""
'odd number
a = 43.435
sa = str(a)
s1 = right(sa,1)
b = val(s1)
Print "original number ";a
if (b mod 2) <> 0 Then a += 0.005
Print Using "##.##"; a
Print String(20,"-")
sa = "":s1 = ""
'even number
a = 43.634
sa = str(a)
s1 = right(sa,1)
b = val(s1)
Print "original number ";a
if (b mod 2) <> 0 Then a += 0.005
Print Using "##.##"; a
Print String(20,"-")
Sleep
```

### Re: Rounding numbers

Unfortunately, your suggestion does not work if the last digit is 1 or 3.

Line 10 in the following suggestion seems to work.

The disadvantage is that DecimalPlaces must be equal to the number of decimal places required in Print Using.

Line 10 in the following suggestion seems to work.

The disadvantage is that DecimalPlaces must be equal to the number of decimal places required in Print Using.

Code: Select all

```
Dim As Double n,a(1 To ...) = {997.931, 997.932, 997.933, 997.934, 997.935, 997.936, 997.937, 997.938, 997.939}
Dim As Integer DecimalPlaces
For i As Long = Lbound(a) To Ubound(a)
n = a(i)
Print "Original number ";n
DecimalPlaces = 2
If (Instr(Str(n),".") > 0) Andalso (Right(Str(n),1) = "5") Andalso (Len(Str(n)) - Instr(Str(n),".") = DecimalPlaces + 1) Then n += Sgn(n) * 5 * (10^(-DecimalPlaces - 1))
Print Using "###.##";n
Print String(20,"-")
Next i
Sleep
```

### Re: Rounding numbers

This also works with sprintf:
I have tested with the following program. If you have seen enough errors, please activate line 92:
This should not obscure the fact that this is not a correction.

It's tinkering from the outside because you don't know what else to do.

In the time you spend on this, you can create a function yourself.

In addition, this does not fix all errors. If you want to see another error, change line 88: decimals = Int(Rnd*10)

Code: Select all

```
#Include "crt.bi"
Dim As Double n,a(1 To ...) = {997.931, 997.932, 997.933, 997.934, 997.935, 997.936, 997.937, 997.938, 997.939}
Dim As Zstring*20 zs
Dim As Integer DecimalPlaces
For i As Long = Lbound(a) To Ubound(a)
n = a(i)
Print "Original number ";n
DecimalPlaces = 2
If (Instr(Str(n),".") > 0) Andalso (Right(Str(n),1) = "5") Andalso (Len(Str(n)) - Instr(Str(n),".") = DecimalPlaces + 1) Then n += Sgn(n) * 5 * (10^(-DecimalPlaces - 1))
sprintf(zs,"%.*f",DecimalPlaces,n)
print zs
Print String(20,"-")
Next i
Sleep
```

Code: Select all

```
#Include "crt.bi"
Function sprintfTest(number As Double, decimals As Double) As String
Dim As String formatstring,exponent
Dim As Zstring*50 zs
Dim As Double n
zs = Str(number) 'Copy the number as string
If Instr(zs,"e") Then 'Separate mantissa and exponent
exponent = Right(zs,Len(zs)-Instr(zs,"e")+1)
zs = Rtrim(zs,exponent)
End If
n = Val(zs)
formatstring = "%." & Str(decimals) & "f"
sprintf(zs,formatstring,n)
If Instr(zs,".") Then 'If decimal point is present
zs = Rtrim(zs,"0") 'Remove the zeros at the end, if present
zs = Rtrim(zs,".") 'Remove the point at the end, if present
End If
zs = zs & exponent
'A positive number should be preceded by a space:
If (Left(zs,1) <> "-") Then zs = Space(1) & zs
Return zs
End Function
Function RoundDouble(number As Double, decimals As Double) 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
'If s = "0" Then sign = Space(1) 'The zero has no sign
s = sign & s & exponent
Return s
End Function
'testing:
'Randomize
Dim As Double n,nsign,e,esign,decimals
Dim As String s1,s2
Do
'Make up the number:
n = Fix(Rnd*(10^Int(10*Rnd)))/(10^Int(5*Rnd))
nsign = Iif(Rnd<0.5,-1,1)
n = nsign*n
decimals = Int(Rnd*5)
'Printout:
Print "Number: ";Space(5);n,"decimals: ";decimals
s1 = RoundDouble(n,decimals)
'If (Instr(Str(n),".") > 0) Andalso (Right(Str(n),1) = "5") Andalso (Len(Str(n)) - Instr(Str(n),".") = Decimals + 1) Then n += Sgn(n) * 5 * (10^(-Decimals - 1))
s2 = sprintfTest(n,decimals)
Print "RoundDouble: ";s1
Print "sprintfTest: ";s2
If s1<>s2 Then Print "Different, any key to continue...":Sleep
Print String(30,"-")
Loop
```

It's tinkering from the outside because you don't know what else to do.

In the time you spend on this, you can create a function yourself.

In addition, this does not fix all errors. If you want to see another error, change line 88: decimals = Int(Rnd*10)

### Re: Rounding numbers

@ badidea, caseih, neil

Thanks for the helpful comments.

Thanks for the helpful comments.