modelica-tools / FMUComplianceChecker

FMI Compliance Checker for validation of FMUs 1.0 and 2.0
BSD 3-Clause "New" or "Revised" License
42 stars 31 forks source link

Improve "time" (double) printing in simulation outputs #69

Closed binghe closed 1 year ago

binghe commented 1 year ago

Hi,

When I run this program with parameters -s 1.5 -h 0.1 (up to 1.5s, with 0.1s steps), I got outputs like this:

"time","p","q","_output"
0.0000000000000000E+00,1,0,0
1.0000000000000001E-01,1,0,0
2.0000000000000001E-01,1,0,0
3.0000000000000004E-01,1,0,0
4.0000000000000002E-01,1,0,0
5.0000000000000000E-01,1,0,0
5.9999999999999998E-01,1,0,0
6.9999999999999996E-01,1,0,0
7.9999999999999993E-01,1,0,0
8.9999999999999991E-01,1,0,0
9.9999999999999989E-01,1,0,0
1.0999999999999999E+00,1,0,0
1.2000000000000000E+00,0,1,1
1.3000000000000000E+00,0,1,1
1.4000000000000001E+00,0,1,1
1.5000000000000000E+00,0,1,1

As you can see, the values shown in the "time" column are quite ugly. This is due to the rounding issues that many common used "decimal" values (like 0.1, 0.2) cannot be precisely represented in binary-based IEEE 754 floating format. And the native algorithm behind printf just give you the above results.

This is because you used "%.16E" formats to print doubles. I understand that "%lf" is also not a good choice. But there's another way by using some advanced algorithms.

In my patch, with help of David M. Gay's rounding algorithm (taken partially from [1] as third-party sources), the situation gets much better. Now I have the following outputs instead: (It's still not perfect but the situation heavily depends on the specific values, e.g. changing the step to 0.2s results in better shapes of more values).

[1] https://github.com/jwiegley/gdtoa

"time","p","q","_output"
0.0,1,0,0
0.1,1,0,0
0.2,1,0,0
0.30000000000000004,1,0,0
0.4,1,0,0
0.5,1,0,0
0.6,1,0,0
0.7,1,0,0
0.7999999999999999,1,0,0
0.8999999999999999,1,0,0
0.9999999999999999,1,0,0
1.0999999999999999,1,0,0
1.2,0,1,1
1.3,0,1,1
1.4000000000000001,0,1,1
1.5,0,1,1

I only modified the printing code of "time", for FMI2 only. You may want to use it also on FMI1 related code, or use it to print all double floats.

Regards,

Chun Tian