As someone who did Fortran for over 30 using code libraries some written 60 
years ago. The epsilon approach is baked in.

I think there are methods in some Java test frameworks where you can do an 
Assert that will automatically handle epsilon internally.

Best,
Dave

Sent from my iPhone

> On Sep 25, 2023, at 7:10 AM, Sood, Harinder <hs...@owlcyberdefense.com> wrote:
> 
> Floating point comparison is typically done with +- delta as Mike suggested.
> 
> 
> Sincerely,
> Harinder Sood
> 
> 
> Senior Program Mnager
>  hs...@owlcyberdefense.com
>  240 805 4219
>  owlcyberdefense.com
> 
> The information contained in this transmission is for the personal and 
> confidential use of the individual or entity to which it is addressed. If the 
> reader is not the intended recipient, you are hereby notified that any 
> review, dissemination, or copying of this communication is strictly 
> prohibited. If you have received this transmission in error, please notify 
> the sender immediately.
> 
> -----Original Message-----
> From: Steve Lawrence <slawre...@apache.org> 
> Sent: Monday, September 25, 2023 10:01 AM
> To: dev@daffodil.apache.org
> Subject: Re: Comparing Floating Point numbers
> 
> Based on what I've learned today from reading that bug, I think in Java at 
> least, float -> string -> float will give you back the exact same float. Note 
> that string -> float -> string could give a different result, since multiple 
> strings can map to the same float, but a float maps to only a single string.
> 
> Java doesn't actually round when converting a float to a string. Instead it 
> finds the shortest string representation that can be uniquely mapped back to 
> the original float. The bug I linked below is about how Java didn't find the 
> shortest. For example, "1.0E23" and "9.999999999999999E22" both map to the 
> exact same float. Older versions of Java output the latter, newer version of 
> Java output the former.
> 
> But even though it didn't output the shortest, and are different decimal 
> representations, both of those strings uniquely map back to the exact same 
> float.
> 
> So although users must be aware that float values in the infoset might not be 
> accurate to the original value, we can be guaranteed that if an infoset 
> string is converted to a Java float, it will at least be the exact same float 
> value that Daffodil wrote to the infoset.
> 
> And so for the purposes of TDML comparisons, it should all be exactly the 
> same.
> 
> For these reasons, I don't actually think creating a special raw 
> representation actually fixes anything. The decimal string already maps back 
> to the original float exactly. The real issues with floats is when you start 
> doing math, or the original data was a string. That's when you start losing 
> precision and get funky results. I don't there are any actual issues with the 
> infoset conversion itself.
> 
>> On 2023-09-25 08:57 AM, McGann, Mike wrote:
>> One thing to note is that by putting a value in a TDML document such as 
>> "12.34e56" it is actually a string. Comparing that to a floating-point value 
>> is going to require a conversion from string and that could invoke a 
>> rounding step if it cannot be accurately represented by a float. If you 
>> really want to compare two floating points exactly, using a binary 
>> representation is probably the best such as putting in something like 
>> 0x1234p56. At least that is how I think I understand it. Floating point math 
>> is a deep rabbit hole that can be followed. That is probably overkill for 
>> TDML.
>> 
>> // Mike
>> 
>> -----Original Message-----
>> From: Steve Lawrence <slawre...@apache.org>
>> Sent: Monday, September 25, 2023 08:07
>> To: dev@daffodil.apache.org
>> Subject: Re: Comparing Floating Point numbers
>> 
>> +1 for type aware comparisons. It should be a very small change to 
>> +this
>> function:
>> 
>> https://github.com/apache/daffodil/blob/main/daffodil-lib/src/main/sca
>> la/org/apache/daffodil/lib/xml/XMLUtils.scala#L1098
>> 
>> And just need to add xsi:type to a few expected infosets that are 
>> sensitive to the issue.
>> 
>> Note that I *think* this might be the bug that caused the change:
>> 
>> https://bugs.openjdk.org/browse/JDK-4511638
>> 
>> Based on that, it sounds like the issue is that Java wasn't creating 
>> the shortest possible decimal representation, but the representation 
>> it did create still parses back to the same floating point 
>> representation. So we *probably* don't even really need epsilon 
>> comparison, we just need type aware comparison, and can still expect 
>> the floating point values to be exactly the same.
>> 
>> Although epsilon comparison is the right way to compare floats, my 
>> concern is that we might add some bug in Daffodil where we do math 
>> wrong and end up with a very very very slightly wrong answer and it 
>> would be hidden. But if our epsilon is small enough, maybe that amount 
>> precision error is fine?
>> 
>> Note that according to that JDK issue, the change was made in Java 19, 
>> so if we add any conditional logic on java version, we should check if 
>> it's at least 19. I guess if we do need epsilon comparisons we could 
>> only do it for java 19 and newer. Older versions would expect exact 
>> values and so would catch any off by very very small amount bugs. That 
>> might be adding unnecessary complication though.
>> 
>> 
>>> On 2023-09-24 12:09 PM, Mike Beckerle wrote:
>>> So Java 21 produces different floating point values in a few cases. 
>>> Some of our tests (4) are sensitive to this.
>>> 
>>> The "right way" to compare floating point numbers is like this:
>>> 
>>> If(Math.abs(A - B) < epsilon)
>>> 
>>> The TDML runner has outstanding bug
>>> https://issues.apache.org/jira/browse/DAFFODIL-2402 which is to add 
>>> the ability to put xsi:type="double" for example on the expected 
>>> infoset, and this instructructs the (schema unaware) TDML runner to 
>>> do comparison using some sort of epsilon comparison like the above
>>> 
>>> Does that seem like the right fix for this?
>>> 
>>> The only alternative I can think of is some sort of conditional 
>>> infoset construction, so that the expected values can vary for different 
>>> JVMs.
>>> 
>>>> On Sat, Sep 23, 2023 at 2:13 PM Mike Beckerle <mbecke...@apache.org> wrote:
>>> 
>>>> 
>>>> JVM 21 LTS is now out.
>>>> 
>>>> So I decided to try to building Daffodil using it. My WIP PR is
>>>> https://github.com/apache/daffodil/pull/1090
>>>> 
>>>> It looks pretty close.
>>>> 
>>>> The --release 8 option for javac is now deprecated. So I 
>>>> conditionalized that.
>>>> Fixed some deprecated calls.
>>>> 
>>>> Remaining issues:
>>>> 
>>>> 2 more deprecated calls (hence fatal warnings turned off for now)
>>>> 
>>>> 5 tests fail. One each in these 3 test classes
>>>> 
>>>> org.apache.daffodil.TresysTests.test_BG000
>>>> 
>>>> org.apache.daffodil.section13.text_number_props.TestTextNumberProps.
>>>> test_textNumberPattern_exponent01
>>>> 
>>>> 
>>>> org.apache.daffodil.section05.simple_types.TestSimpleTypes.test_doub
>>>> le_binary_06
>>>> 
>>>> All 3 of those failures are floating point related like this: 
>>>> (highlighted digit isn't output any more)
>>>> 
>>>> [error] Expected (attributes stripped)
>>>> [error]    <d_02>9.8765432109876544E16</d_02>
>>>> [error] Actual (attributes ignored for diff) [error] 
>>>> <ex:d_02>9.876543210987654E16</ex:d_02>
>>>> 
>>>> The Expected has one more digit 4 at the end.
>>>> 
>>>> 1 other test failure is for reasons unknown. Possible change in 
>>>> regex behavior?
>>>> 
>>>> 
>>>> org.apache.daffodil.io.layers.TestJavaIOStreams.testBase64ScanningFo
>>>> rDelimiter1
>>>> 
>>>> One CLI test failure:
>>>> 
>>>> 
>>>> org.apache.daffodil.cli.cliTest.TestEXIEncodeDecode.test_CLI_Encode_
>>>> Decode_EXI
>>>> 
>>>> 
>>>> 
>>> 
>> 
> 

Reply via email to