0

I'm using Delphi7.

GetLocaleFormatSettings(1038, FS);
FS.DecimalSeparator := '.';
FS.ThousandSeparator := #0;
FS.NegCurrFormat := 5;
FS.CurrencyString := '';

XMLNode.Text := FloatToStrF(Query.FieldByName('Quantity').AsFloat, ffGeneral, 18, 2, FS);

Quantity DB field (Firebird) is 18,2 DECIMAL.

The problem: If the value of Quantity is 15.6, sometimes FloatToStrF will give back 15.600000012 or 15.59999996 or similar. I'm putting the result into an XML file with strict validation (18,2) and it is generating an error. Restarting the computer may solve the problem.

I'm thinking this is a floating point issue, but what can I use instead of FloatToStrF to convert a decimal number to string?

Thank you!

Steve
  • 2,510
  • 4
  • 34
  • 53
  • If you request 18 digits, you get 18 digits -- with fuzz. – Andreas Rejbrand Jul 04 '18 at 09:06
  • @DavidHeffernan: floating-point arithmetic does not cause non-deterministic behavior. That is a different software problem. Why did you mark this as a duplicate of a question that does not address the question asked here? – Eric Postpischil Jul 04 '18 at 10:17
  • @AndreasRejbrand: Floating-point arithmetic ought to round as needed by the destination format, but it should not cause apparently random “fuzz.” The same rounding operation with the same input ought to produce the same output every time. – Eric Postpischil Jul 04 '18 at 10:18
  • @Steve: Are you saying the exact same input produces different input? It is not “15.6” computed by one method one time and “15.6” computed by a different method another time? Software often shows a limited amount of a floating-point value, so that two numbers near 15.6 might both be printed as “15.6”. Are you sure you had exactly the same value being passed to `FloatToStrF`? – Eric Postpischil Jul 04 '18 at 10:20
  • @Eric I don't believe that the question is really claiming non-deterministic behaviour. I think that the asker just doesn't understand why 18.6 cannot be exactly represented. The two values given are just examples of the sort of values that are observed. – David Heffernan Jul 04 '18 at 10:25
  • @DavidHeffernan: Then the question should be clarified before being closed. As posted, it asks about non-deterministic behavior. Maybe the author is mistaken or presented it incorrectly, but jumping to conclusions prevents tricky issues from coming to light even if the jump happens to be correct most of the time. – Eric Postpischil Jul 04 '18 at 10:31
  • @Eric Then we'd close it for a different reason (no mcve for instance). But it's pretty easy to be confident that this is the reason since we know that `FloatToStrF` is deterministic, and we surely know that reading a value from a database is deterministic. – David Heffernan Jul 04 '18 at 10:37
  • @DavidHeffernan: You “know” this if software has no bugs and no unexpected behaviors arise. Which of course is always true because programmers are perfect and we know everything about programming already. But in May I reported a Clang bug that evaluated `memcmp` incorrectly, which I caught only after others incorrectly answered that the manual was wrong and `memcmp` was behaving correctly or gave other explanations. Engineering requires figuring out what is really going on, not jumping to conclusions. We should ask first and decide later. – Eric Postpischil Jul 04 '18 at 10:52
  • @EricPostpischil Delphi's `FloatToStrF` is well understood. As for the actual close reason, the regular view from meta is that if a question is closed for the wrong reason, then that isn't that big a deal. Not worth trying to change it. If the asker comes back with a [mcve] showing non deterministic behaviour then that's a different story. But the asker seems to have asked and then gone away. – David Heffernan Jul 04 '18 at 10:54
  • I haven't gone away David, why did you close my question while linking an irrelevant answer? In Firebird DECIMAL 18,2 means 18 normal digits and 2 to the right of the decimal point. Thus there should be no more than 2 digits. – Steve Jul 04 '18 at 16:39
  • To clarify it once more: I'd like to convert a decimal (18,2) value coming from the database to a string that has no more than 2 digits to the right of the decimal point. How can I do this? – Steve Jul 04 '18 at 16:44
  • That's not what you asked. Anyway, if your data is decimal, why are you converting to float? This is of course the reason why you don't get the number you expect. 18.6 cannot be represented in a binary floating point data type. That's what you can learn at the dupe. If you have decimal data, keep it as decimal. – David Heffernan Jul 04 '18 at 20:39
  • TIBCQuery, the components I'm using doesn't have AsDecimal. I can only convert to Float. In the end I need it in a String. – Steve Jul 04 '18 at 21:41
  • @Steve: I have the privilege to reopen floating-point questions, but we would need to see a properly posed question. One issue is that you did not answer my question (fourth from the top) about whether the **exact same** value produces different output. If you can provide a [minimal complete verifiable example](https://stackoverflow.com/help/mcve) where **one** value computed in **one** way produces different outputs, we would have a problem worth examining. Or, if your problem is to handle 20-digit decimal numerals without rounding errors, that is a different tack that could be addressed. – Eric Postpischil Jul 05 '18 at 00:45
  • @DavidHeffernan: By the way, I would generally be inclined to agree the probability favors different computations producing different results that are displayed as the same numeral by default formatters but of course produce different displays when formatted with more precision. But the question states “Restarting the computer may solve the problem.” That adds weight toward non-determinism rather than the common floating-point issues. `memcmp` is certainly as well understood as Delphi’s `FloatToStrF` but nonetheless had a bug. Bugs can only be found if we are willing to find them. – Eric Postpischil Jul 05 '18 at 00:47
  • @eric Let's see a repro. I don't believe that a restart changes anything. – David Heffernan Jul 05 '18 at 05:43
  • There is certainly much confusion and ambiguity in the question. But I think the simple answer is: use ffFixed instead of ffGeneral. ffGeneral ignores the Decimal parameter. http://docwiki.embarcadero.com/Libraries/Tokyo/en/System.SysUtils.TFloatFormat – David Dubois Jul 05 '18 at 12:30

0 Answers0