guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: redoing SCM representation in 2.2


From: Ken Raeburn
Subject: Re: redoing SCM representation in 2.2
Date: Thu, 19 May 2011 03:58:31 -0400

On May 17, 2011, at 14:59, Mark H Weaver wrote:
>> But the question I was after was, even if we want to use the full
>> range of the values, do we need the entire set to be representable *in
>> immediate form*?  I doubt the very largest and smallest values are
>> used often, so making just those values use heap storage probably
>> wouldn't be too costly in space.
> 
> In principle, I agree with you that it might be reasonable to cut the
> exponent range of immediate doubles in half in order to gain an extra
> bit of tagging information.  Unfortunately, it seems to me that the
> details of the IEEE 754 floating-point formats would make the required
> checks rather expensive.
> 
> The exponent field of an IEEE 754 binary floating-point number is not
> stored in twos-complement format, but is instead "biased", meaning that
> a constant is added to the true exponent of two, such that 1 represents
> the smallest representable exponent, and 2^EXPBITS-2 represents the
> largest representable exponent.  The worse problem is that a 0 in the
> exponent field means that the number is a (signed) zero, and 2^EXPBITS-1
> means that the number is either infinity of a NaN.

So the most interesting exponent values to keep expressible as immediates would 
include (hex) 000, 7ff, and values near 3ff and 400, right?  One way of looking 
at that is, in the top 3 exponent bits, four of the eight possible patterns 
(000, 111, 011, 100) represent the most interesting floating point values, and 
the rest can be relegated to heap storage.  If we leave it at that, actually, 
some of the really-small and really-large numbers could be encoded immediately, 
but values of medium magnitudes could not.

Hmm... we'd want to map field values of 0, 7, 3, and 4 to one value, and 1, 2, 
5, and 6 to another.  How about: "(field+1) & 2"?  I think that gives you 0 for 
0/inf/nan and values with large positive or negative exponents, and for values 
closer to 1 in magnitude, and gives 2 for finite values with medium-range 
magnitudes.  (I threw some code together testing some powers of 10; it looks 
like 1.0e-231 and smaller, 1.0e-76 through 1.0e77, and 1.0e232 and larger, 
along with 0/nan/inf, would get classified together that way.)

Make the "field+1" part of the encoding, and all those values encode in a form 
that has that specific bit clear (or bits could be shuffled to put it 
elsewhere); then values with the bit set would indicate everything other than 
immediate doubles.

A bit more arithmetic trickery might let you swap exponent 000 with 200 and 7ff 
with 5ff, giving you only 0x3ff exponent values you'd want to store 
immediately, same as above, but with only two of the exponent values "stolen" 
for 0/inf/nan.

This is all still only somewhat IEEE-754 dependent, in that it doesn't require 
the existence of inf or nan values, it just twists things around a bit so that 
the IEEE-754 encodings of those values would be among those encoded as 
immediate values.  If a machine like the Vax doesn't support them, no big deal; 
the basic idea still works.


But, what's the case we should optimize for?  I'm guessing that in cases where 
lots of floating point values are encoded and decoded, we're doing lots of math 
or lots of I/O, and I suspect that 0/inf/nan are not nearly as common as finite 
nonzero values in some truncated range.  (And how big a range of exponents do 
most applications need?)  So a variant encoding that uses magic values for 
0/inf/nan that can be easily tested for collectively, much like we do for 
#t/#f/#nil now, and heap encoding for the largest-magnitude exponents, cuts in 
half the number of values we need to be able to encode in immediate form using 
lots of bits, at the cost of a few more magic constants, and a slightly slower 
classify/encode/decode process because of the use of three encodings.  And we 
may be able to streamline usage slightly with a macro or inline function to 
express "tell me if this is a double and if it is also extract the value into 
this variable".

I guess one important question is how important efficient use and encoding of 
the full range of floating point values is compared to other types.  I think 
I'd rather have the wider space for integers and pointers, personally, but I'm 
sure other people's work may have different demands.  And for that matter, I 
don't know if all that much of the 64-bit integer data I ever deal with really 
is outside the 48-bit range, though I could imagine issues coming up with bit 
masks.


> Given this, I don't see an obvious way to steal a bit or two from the
> exponent field without making the associated checks too expensive to be
> worth the benefits.  I think at least two conditional branches would be
> required.  Do you see a clever way around this?  If so, can you please
> post the details?

Correctly predicted branches are generally cheap on most modern architectures, 
I believe.  So I'm not sure how costly it would really be, compared to all the 
other stuff we do.  It would cost a little more than in Andy's proposal, I 
think.

If the test you care about is, "is this a double", then with the first form 
above I guess it would be implemented as "is bit X clear; if not, does the tag 
indicate that it's a double stored in the heap".  So, looks like two tests to 
determine that it isn't a double, and they may or may not be easy to combine 
into one test.  The second form preserves more of the value space for 
non-double values, but would probably take three tests (bit X; 0/nan/inf magic 
constants; heap-double tag) to determine that a value isn't a double.  For a 
value that is a double, hopefully the first test would catch it, most of the 
time.

Ken


reply via email to

[Prev in Thread] Current Thread [Next in Thread]