Note that I had set "equality" in double-quotes, so read on about the details:
I wrote some code that stores Perl objects in a file and retrieves them from there. I'm using my own JSON-based code using text representation to be independent from Perl. When I wrote a self-test checking whether the loaded object is the same as the stored object, I got a surprise:
DB<14> x $self->time() == $other->time()
0 ''
DB<15> x $self->time()
0 4842276.32536854
DB<16> x $other->time()
0 4842276.32536854
DB<17> x $self->time() == $other->time()
0 ''
DB<18> x $self->time() - $other->time()
0 '-2.79396772384644e-09'
So while the numbers output look identical, their internal representation is not. However when I create a JSON representation for both, there is no difference (different numbers this time (as time went on); also note that the order of the fields varies as it's a Perl HASH):
DB<1> x $self->flat
0 '{"time":4842854.29538268,"crc":23407,"use_counter":19}'
DB<2> x $other->flat
0 '{"use_counter":19,"crc":23407,"time":4842854.29538268}'
(The real objects are more complex, but this shows the principle; the time value comes from clock_gettime(CLOCK_MONOTONIC) # useTime::HiRes qw(clock_gettime CLOCK_MONOTONIC)
)
Now I wonder: Should I simply try to compare the numbers as strings (as a work-around), or should I use an elaborate ("correct") solution like https://stackoverflow.com/a/33024979/6607497?
Considering different solutions for the original problem (float number is not equal after saving and restoring it via JSON (and using default string conversion)), I wanted to fix JSON save and restore instead of the floating point comparison.
So after temporarily using string comparison for the floating-point numbers (that would also fix the problem), I switched back to numeric comparison. To make that work, I decided to save the numbers as hexadecimal double representation (Perl's floats are always double internally).
The code basically became:
if ($encode) {
return unpack('H*', pack('d>', $val));
} else {
return unpack('d>', pack('H*', $val));
}
So 5274540.53703853
is saved as 41541eeb225ed6db
, for example.
I cross-checked with C, and it uses the same representation.