< :the previous in number
^ :the list in numerical order
> :the next in number
P :the previous aricle (the previous thread)
N :the next (in thread)
|<:the previous thread
>|:the next thread
^ :the parent (reply-to)
_:the child (an article replying to this)
>:the elder article having the same parent
<:the youger article having the same parent
---:split window and show thread lists
| :split window (vertically) and show thread lists
~ :close the thread frame
.:the index
..:the index of indices
The following small test program:
[1.5, 4.0/3.0].each { |a|
ma = Marshal.dump(a)
b = Marshal.load(ma)
if a == b
puts "Everything is working fine for #{a}"
else
puts "PROBLEM: a is #{a}, b is #{b}, and ma is #{ma.dump}"
end
}
Exposes the following strange behavior:
ruby test.rb
Everything is working fine for 1.5
PROBLEM: a is 1.33333333333333, b is 1.33333333333333, and ma is
"\004010f\0261.333333333333333"
So apparently Marshal *sometimes* changes the value of a
Float when dumped. The problem looks like it is caused by
an attempt to make a platform-independent Marshal format
using an ASCII-decimal like representation, which cannot
accurately express all possible double's. I understand that
this is an impossible problem since different floating point
formats have different sets of expressible points on the real
line. I think it would be more convenient and useful in
scientific computing, however, if we could exactly save and
load floating-point values when we are on a consistent
platform like the IEEE 754 standard, and just want to use
Marshal to save/load on disk or across a network with no
numerical instability. Here is one way to achieve it using a
special byte:
Choose the three most popular floating-point formats, and
give them codes, like
0 = IEE754x86, 1 = SPARC, 2 = MAC68k, 3 = OTHER
Then add a single byte to the end of the Marshal string that
bitwise copies in a platform-dependent format the
6 least-significant bits of the significand, wherever they
may be according to the spec. Then, when loading up a Float,
first read the decimal expansion as usual to get a "close"
value. Next, check the 2-bit format code to see if the native
Float format is the same. If it is, copy over the six bits of
platform-dependent significand over the close value. Now it's
precisely right when the format is the same, and "pretty
close" in other cases. If we're concerned about the size of the
Marshal format, then it would probably do as well to simply
replace the last decimal digit of a maximum-sized decimal
expansion with this special byte, as it contains more information
than a single decimal digit. Then, this special byte would only
incur an extra cost in the relatively small fraction of Float's
that have submaximal decimal expansions. Finally, it's not
hard to see how a single bit can be used instead to indicate
the presence or abscence of the special byte, to further cut
down on space used.
This technique would allow me to do long scientific simulations
that have to load and save lots of intermediate files and over
many different computers working in parallel and communicating
results via network.
What do you all think?
Rudi
(another ruby hack)