# IsZero or SameValue

## Recommended Posts

So i thought 0.1 was representable in floating point, obviously not.

How do i use IsZero() or SameValue in a situation like this.

updownbuttonclick(TObject *Sender, TUDBtnType Button)

{

value += (Button == btNext ? 0.1 : -0.1);

}

What i'm doing now is convert value to a string and then back to fp, this eliminates the cumulative rounding error. How to tackle this with one of those math functions?

Thanks.

Edited by JeanCremers

Quote

IsZero or SameValue

Neither. Spawn of satan, should never have been published.

In your case do all the behind the scenes work using integers and then divide by 10 just when you need the actual value. Or use a decimal type like currency.

Edited by David Heffernan
• 1

1 hour ago, David Heffernan said:

Neither. Spawn of satan, should never have been published.

In your case do all the behind the scenes work using integers and then divide by 10 just when you need the actual value. Or use a decimal type like currency.

🙂

Thanks. I tried the multiply/divide trick, but not with 10 but with 100000 and ran into similar problems. Converting to a string and back to a float at least seems to work against the cumulative issue.

What I propose works and it's better to avoid strings here.

Why not use a string?

FloatToStr(0.1) always makes "0.1", so it avoids the rounding error.

Edited by JeanCremers

```{\$APPTYPE CONSOLE}

uses
SysUtils;

procedure Main;
var
i: Integer;
val: Double;
begin
val := 0;
for i := 0 to 80 do
begin
Writeln(FloatToStr(val));
val := val + 0.1;
end;
end;

begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.```

Output:

```0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
2
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
3
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
4
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8
4.9
5
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8
5.9
5.99999999999999
6.09999999999999
6.19999999999999
6.29999999999999
6.39999999999999
6.49999999999999
6.59999999999999
6.69999999999999
6.79999999999999
6.89999999999999
6.99999999999999
7.09999999999999
7.19999999999999
7.29999999999999
7.39999999999999
7.49999999999999
7.59999999999999
7.69999999999999
7.79999999999999
7.89999999999999
7.99999999999999```

So yeah, not looking such a good idea now.

Why not use integers. You just need to count how many tenths you have. That's the job of an integer.

3 hours ago, JeanCremers said:

So i thought 0.1 was representable in floating point, obviously not.

Once you recognise this, then you are 90% of the way to realising the right solution.

Edited by David Heffernan

I'm doing something like this, for my purposes it works fine.

```
double r = 0.1, inc = 0.1;
String S;
for (int i = 0; i < 80; i++) {
S = FloatToStr(r);
r = StrToFloat(S) + inc;
```

ps, it's not only meant for doing 0.1 , it should also handle other values.

3 hours ago, David Heffernan said:

Spawn of satan, should never have been published.

Why? What's wrong with them?

52 minutes ago, Anders Melander said:

Why? What's wrong with them?

They are invariably used as "solutions" to problems caused by floating point representability issues, but usually are the wrong solution.

58 minutes ago, JeanCremers said:

ps, it's not only meant for doing 0.1 , it should also handle other values.

Then you are going to need to work out what your problem really is. Because it hasn't been stated here. If you want to work with numbers that have a finite number of decimal digits, then use a decimal type. It is precisely why such things exist.

Edited by David Heffernan

3 minutes ago, David Heffernan said:

They are invariably used as "solutions" to problems caused by floating point representability issues, but usually are the wrong solution.

Okay, so there's basically nothing wrong with the functions. Thanks.

8 minutes ago, David Heffernan said:

Then you are going to need to work out what your problem really is. Because it hasn't been stated here. If you want to work with numbers that have a finite number of decimal digits, then use a decimal type. It is precisely why such things exist.

I'm ok with my current solution, it does what i need it to do.

32 minutes ago, Anders Melander said:

Okay, so there's basically nothing wrong with the functions.

Right. They do what they are meant to do. It's just that they aren't actually useful for anything.

54 minutes ago, JeanCremers said:

I'm ok with my current solution, it does what i need it to do.

If you use type "currency" instead of "double", it would work too and you can avoid most of the conversions between numerical and string types. Currency can keep 4 decimal places (even the 0.1 🙂 ).

Edited by Vandrovnik

31 minutes ago, David Heffernan said:

They do what they are meant to do. It's just that they aren't actually useful for anything.

So how would you compare floats with tolerance?

```function BinarySearch(const List: TArray<Double>; Value: Double; Tolerance: Double): integer;
begin
var Lo := 0;
var Hi := High(List);
while (Lo ≤ Hi) do
begin
var Mid := (Lo + Hi) div 2;
if SameValue(List[Mid], Value, Tolerance) then
exit(Mid);
if List[Mid] < Value then
Lo := Mid+1
else
Hi := Mid-1;
end;
Result := -1;
end;```

24 minutes ago, Anders Melander said:

So how would you compare floats with tolerance?

Certainly not like that because this will not consider a value next to the potential find that is a closer match - when the list has a different count of elements the result could be different.

3 minutes ago, Stefan Glienke said:

Certainly not like that because this will not consider a value next to the potential find that is a closer match - when the list has a different count of elements the result could be different.

match, matcher, matchest? The tolerance determines the result, isn't it?

• 1

1 hour ago, Vandrovnik said:

If you use type "currency" instead of "double", it would work too and you can avoid most of the conversions between numerical and string types. Currency can keep 4 decimal places (even the 0.1 🙂 ).

Can't do, i need type double, its for a script language and it has no currency type, but it has double. And this works for my needs.

Edited by JeanCremers

1 hour ago, Stefan Glienke said:

Certainly not like that because this will not consider a value next to the potential find that is a closer match - when the list has a different count of elements the result could be different.

You're right. I tried to come up with a trivial example - and failed. Anyway, you get the point.

Whynot? UItext := Format('%f.%f', [MN div 10, MN mod 10]);

MN := round(anumber*10);

when MN is Integer .  _Trunc or _Floor may be available in your Script as well.

5 hours ago, Attila Kovacs said:

match, matcher, matchest? The tolerance determines the result, isn't it?

Upper and lower bound - look it up

3 minutes ago, Stefan Glienke said:

Upper and lower bound - look it up

Ok I thought he cited it from a working lib... @Anders Melander how dare you!??

38 minutes ago, Attila Kovacs said:

Ok I thought he cited it from a working lib... @Anders Melander how dare you!??

Well, it's just pseudo code that happens to look a lot like Delphi code 🙂 .

In my defense, I think it actually works as I intended; It will return a match within the tolerance but it might not return the closest match.

• 1

14 hours ago, JeanCremers said:

Can't do, i need type double, its for a script language and it has no currency type, but it has double. And this works for my needs.

This certainly changes things!