Comparison of variables of different type with conversion returns incorrect result

Asked

Viewed 858 times

5

I have the following code

var
  Valor1: string;
  Valor2: Double;
begin
  Valor1 := '150.15';
  Valor2 := 150.15;

  If StrToFloat(Valor1) = Valor2 then
     ShowMessage('Iguais');
end;

In this situation, sometimes Delphi understands that the values are different, however, if I use the code below they are considered equal

    var
      Valor1: string;
      Valor2: Double;
  Valor2: Double;
    begin
      Valor1 := '150.15';
      Valor2 := 150.15;
      Valor3 :=  StrToFloat(Valor1);

      If Valor3 = Valor2 then
         ShowMessage('Iguais');
    end;

Note: in the cited example I am setting the values directly to the variable, however, the problem I had occurred from reading a serial data, but even if I use the function FormatFloat It kept happening, and if I gave a debug in the variables the values were equal, and yet were not considered equal in the if

2 answers

5


If you need exact equality you can’t use one Double. It is not possible in all cases. It has a binary format that cannot represent all possible numbers, so something that looks the same may not be, it depends on the form it was obtained. Behold What is the correct way to use the float, double and decimal types?.

I’m not sure about Delphi because there’s a difference. Either this code is a little different from the real where it got the result, or the language has some optimization that brings a different result, which is strange, after all the fact of storing in a variable should not change the semantics, but each language with its preference, We’ve seen on this page that there’s weird stuff on Delphi. You may be misreading something.

Extendend does not solve the problem, after all he is a Double more accurately, but still inaccurate, at best disguises it, which is worse. It will work, but it won’t be right. It may never go wrong, but by definition it can.

Fiat 147 todo detonado andando pelas ruas

It has to solve if to spread roundabouts for the whole code, but it is Gambi of the thick.

The only real solution is a decimal type instead of binary, the binary exponent does not allow all values (2) that we are used to (10).

I am not familiar with the implementation of Currency of Delphi, he would be the solution, but by the observation of Bacchus he was poorly done (we are not both sure). A decimal type should be in essence an integer, not necessarily Integer with a built-in exponent indicated to decimals (has other ways to implement this). There it works and is right.

I have a reply which is kind of a compendium on the subject.

Correct example in Java.

See more.

  • I don’t understand why the Extended disguises the result, since in Delphi it represents a high precision floating point value. can explain?

  • 1

    @Juniors see the linked answer, the fact of being floating point already indicates that the real value is not what you see: What is the correct way to use the float, double and decimal types?

  • @Bacco then, I read and understand, what I would like to be explained would be the "disguise", in Delphi the type cast has to be done correctly, if not the "disguise" appears. The return of StrToFloat the case in question is being used incorrectly, the Extended is a Long Double, what I understand is that this wanting to keep a truck in the wave of a beetle.

  • It’s different, the Long Double is a truck instead of a VW Beetle. If you want to find a needle in one of them in which you have more area to look? That’s why you disguise more.

  • 1

    @Juniors you in the first comment said it represents floating point, now said it is long, I didn’t get it right. Is it float or is it long? I have no practice with the specific types of Delphi.

  • 2

    @Júniormoreira I just saw a manual (very bad by the way) that calls everything "decimal", mixing float with decimal (which are completely different things). The fact is that if Extended is the same as C’s Long, it is whole and precise. If it is equal to C’s Float, it is inaccurate (and you don’t see the exact value in most cases). It seemed to me that the only type of value with decimal without problems for Delphi would be the Currency

  • 2

    ... and even then, it seems that it is only "accurate" by forcing rounding in the float. I would have to see the actual implementation in order to be able to reflect better. The fact is that anything that is not stored with literal value is not good for financial transactions. If someone with experience in Delphi can give more technical details, thank you.

  • @Bacchus O fato é que qualquer coisa que não seja armazenada com valor literal não presta para operações financeiras. Here’s the main point, we had a problem with rounding, to solve we had to change to Numeric (Firebird) and in Delphi the fitting was the Extended, all that was Real, Double was a problem. Numeric stopped recording "xxx.xxxxxxxxxxxxxxxxx" from Doubleprecision/Float and started recording exactly what we sent. Now someone with more experience on the subject would be most welcome.

  • 2

    I mean, he disguised himself better and now they’re not seeing the problem anymore, but he’s there ready to explode at some point. Too bad I can’t put an image in comment...

  • @Júniormoreira I would not have much to add, it would be the case of a deal with affection in the post that Maniero linked, it deals with the problem independent of language and platform. Firebird has an interesting thing, you can use Int, but with scale (-2, for example) to the decimals. So, for sure the number you’re looking at is what’s been stored. A float, which looks on the screen like 2.5 million can be internally stored as 2.4999999999999999999999938271, and you will only notice when the results do not match. It’s the nature of the float.

  • An int with scale -2 would already look like this: 2.50, internally stored as 250 (0x000000FA), has nowhere to go wrong. And that goes for any situation, because if the DB or the language doesn’t have a native type, you can create your own functions for that. Anyway the system will have to deal with rounding even, and that is the business rule or legislation, and not the language. Or do as our secretary of the farm, that in a joke worthy of Brazil, accepts errors of a penny in certain situations.

Show 6 more comments

3

Whether to use the function StrToFloat consider passing it a string with ',' and not '.' to decimal separator.

Another detail is the Variable Type that will receive the result.

In the System.SysUtils we have:

function StrToFloat(const S: string): Extended;

var
  Valor1: string;
  Valor2: Extended;
begin
  Valor1 := '150,15';
  Valor2 := 150.15;

  If StrToFloat(Valor1) = Valor2 then
     ShowMessage('Iguais');
  • Just one detail, the decimal separator can be variable between '.' and ',' according to the formatsettings. If not initialized by the system, it gets the windows regional settings by default.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.