# How can I get same rounded value using SimpleRoundTo?

## Recommended Posts

Hello,

Using Delphi 10.4.2 I get different rounded values using below code. Purpose is to round up and have 13.98 for both.

uses
System.Math;

procedure TForm1.Button1Click(Sender: TObject);
var
ToBeRounded: Double;
Rounded: Double;
begin
ToBeRounded := 55.9 * 0.25;
Rounded := SimpleRoundTo(ToBeRounded, -2);
ShowMessage(ToBeRounded.ToString() + ' ' + Rounded.ToString()); // ToBeRounded is 13.975 and Rounded is 13.97 at this point
Rounded := SimpleRoundTo(13.975, -2);
ShowMessage(Rounded.ToString); // Rounded is 13.98 at this point
end;

If one reads help file it has following table for expected results

I do not have deep floating point knowledge. I basically know they have a lot more digits than displayed.

My question is, how can I always get 13.98 as result using multiplications and such.

Thanks & Regards,

Ertan

13.98 can't be exactly represented in a binary floating point type like double. What you can do is store the closest representable number to 13.98.

However, unfortunately Delphi's library code that converts between decimal text and binary floating point is rather poor and has fallen behind just about every other mainstream language. The documentation you link to is pretty flawed too because it doesn't acknowledge representability.

What problem are you trying to solve? Are you working with currency for instance? In which case binary floating point is not what you need.

7 hours ago, David Heffernan said:

What problem are you trying to solve? Are you working with currency for instance? In which case binary floating point is not what you need.

These numbers are read from a scale generated barcode for calculating price of a product like cheese. Barcode has weight, unit price and amount of that weight printed in numbers on it. Application was calculating total amount 0.01 wrongly. I was trying to fix that old code to have exact amount displayed on that barcode.

Turns out Currency type is the way to go. I tried it and works correctly on all samples I have. The code otherwise is same including rounding functions.

For what it's worth, we use floating point numbers a lot here in our scientific work, and the accuracy is critical. Add in unbiased rounding rules (i.e. banker's rounding), multiplication, division, and averaging first, and it's even more complicated. Between Delphi, C#, and the shared SQL Server backend, I got so frustrated with rounding variations, storage of numbers (e.g. 1.025 sometimes stored as 1.025000001 or 1.0249999999) that I ended up writing my own rounding routines using string conversions, custom digit management, etc.

34 minutes ago, BruceTTTT said:

For what it's worth, we use floating point numbers a lot here in our scientific work, and the accuracy is critical. Add in unbiased rounding rules (i.e. banker's rounding), multiplication, division, and averaging first, and it's even more complicated. Between Delphi, C#, and the shared SQL Server backend, I got so frustrated with rounding variations, storage of numbers (e.g. 1.025 sometimes stored as 1.025000001 or 1.0249999999) that I ended up writing my own rounding routines using string conversions, custom digit management, etc.

Isn't your problem simply that you are using wrong type. You should be using a decimal type.

A very long time ago and what feels like a far off galaxy

A very long time ago and what feels like a far off galaxy

A very long time ago and what feels like a far off galaxy

A very long time ago and what feels like a far off galaxy

A very long time ago and what feels like a far off galaxy.....

I was part of a small team than wrote accounting software for our UK and international customers.

All the prices, totals, decimal quantities, fractional quantities were represented as integers or long integers.

The long integers having 15 digits of significance; not a floating point number in sight.

All decimal places and fractial separators were implicit until it came to displaying them.

No rounding errors crept in.

I remember this as an example of a good design choice by the lead developer.

• 4

Just to agree with everyone re: floating point use I point out that "1.025 sometimes stored as 1.025000001 or 1.0249999999" is an incorrect statement. This is how the numbers are DISPLAYED when converted to decimal. They are stored in BINARY floating point, typically based on the standard IEEE 754-1985 (see https://en.wikipedia.org/wiki/IEEE_754-1985). Before everyone shouts: I know this is not the latest version of IEEE-754 - but linking to the 1985 version (which only discusses binary floating point) is easier when the discussion is limited to the Delphi (or C++) floating point types.

2 hours ago, Roger Cigol said:

Just to agree with everyone re: floating point use I point out that "1.025 sometimes stored as 1.025000001 or 1.0249999999"﻿ is an incorrect statement. This is how the numbers are DISPLAYED when converted to decimal. They are stored in BINARY floating point, typically based on the standard IEEE 754-1985 (see https://en.wikipedia.org/wiki/IEEE_754-1985). Before everyone shouts: I know this is not the latest version of IEEE-754 - but linking to the 1985 version (which only discusses binary floating point) is easier when the discussion is limited to the Delphi (or C++) floating point types.

In fact, when you put 1.025 into a double precision variable, what is stored is the closest representable value to 1.025 which happens to be 1.024999999999999911182158029987476766109466552734375.

13 hours ago, David Champion said:

I was part of a small team than wrote accounting software for our UK and international customers.

All the prices, totals, decimal quantities, fractional quantities were represented as integers or long integers.

The long integers having 15 digits of significance; not a floating point number in sight.

I once worked at a place that made calculation software for the construction business. When I started there all numbers were stored internally as strings. Apparently someone there knew about the problems associated with floating point numbers and had decided to solve the problem by representing all values as decimal formatted strings instead. Problem solved, right? Well, not exactly because every time they needed to recalculate values (i.e. just about every time the user did anything in the application) the strings were converted to floats, recalculated and then back to strings. Need to adjust the precision? Easy; Just truncate the length of the string. Clever, Eh?

Unfortunately this little "pearl" was the least of their design problems. The whole calculation was represented internally as a tree structure and what do you do when you need a tree structure? You use a TTreeView of course! No need to reinvent the wheel.

A good example of what can happen when you turn your mockup or proof of concept into a product without a rewrite.

8 minutes ago, David Heffernan said:

In fact, when you put 1.025 into a double precision variable, what is stored is the closest representable value to 1.025 which happens to be 1.024999999999999911182158029987476766109466552734375.

Good thing we got that settled. *cough*Asperger*cough* 🙂

• 1

3 hours ago, Anders Melander said:

A good example of what can happen when you turn your mockup or proof of concept into a product without a rewrite.

Manager: "You mean that program you showed us yesterday? Of course we're going forward! It looked pretty much finished. How much time do you need to polish it a bit so we can put it into production?"

• 3