Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add flbit-field #882

Merged
merged 1 commit into from
Oct 30, 2024
Merged

add flbit-field #882

merged 1 commit into from
Oct 30, 2024

Conversation

mflatt
Copy link
Contributor

@mflatt mflatt commented Oct 26, 2024

The flbit-field operation is analogous to bitwise-bit-field, but it extracts bits from a flonum.

This operation seems useful to the Herbie developers, particularly at a use site where the flonum argument can be unboxed and the result is a fixnum, so that it can work without allocating.

@mnieper
Copy link
Contributor

mnieper commented Oct 28, 2024

This is a candidate procedure for adding to a revision of R6RS. I suggest aligning it to the semantics and naming conventions set in R6RS. The procedures in R6RS dealing with IEEE representations are described in section 2.8 of the standard libraries. As the bitwise procedures act on exact integer objects, the procedures from 2.8 act on (inexact) real number objects (which need not coincide with the set of flonums).

This suggests (ieee-single-bit-field x) and (ieee-double-bit-field x) as names. They would probably also need an endianness argument.

If flbit-field is meant to be analogous to fxbit-field, it should probably also include a reference to single and double and to an endianness. It makes sense for it to coexist with ieee-single-bit-field and ieee-double-bit-field.

@mflatt
Copy link
Contributor Author

mflatt commented Oct 28, 2024

@mnieper — Thanks for your comments.

I don't think this operation is like the functions in 2.8 of the R6RS library, which operate on bytevectors. I don't immediately see a point to new operations on bytevectors, because it's already straightforward (using integer operations) to inspect bits of a floating point number as encoded in a bytevector.

Your point about different IEEE formats is well taken in the context a standard, and I agree that flieee-single-bit-field and flieee-double-bit-field could be sensible names when "flonum" is more loosely defined. In Chez Scheme, though, a flonum is defined to be an IEEE 64-bit floating-point number, so there's no ambiguity in flbit-field. Also, the usefulness of this function seems tied to performance characteristics of a specific implementation, so I'm not sure it would be a great candidate for a standard. My preference would be to stick with the more obvious name flbit-field for Chez Scheme, but I don't feel too strongly about this if others would prefer a longer name.

@mnieper
Copy link
Contributor

mnieper commented Oct 28, 2024

Thank you for your response.

@mnieper — Thanks for your comments.

I don't think this operation is like the functions in 2.8 of the R6RS library, which operate on bytevectors. I don't immediately see a point to new operations on bytevectors, because it's already straightforward (using integer operations) to inspect bits of a floating point number as encoded in a bytevector.

I didn't mean to add new bytevector operations; as you write, there is no point in doing so as there is already a straightforward solution.

I referred to bytevectors to have a template for naming conventions and semantics (single/double, endianess, domain of argument).

Your point about different IEEE formats is well taken in the context a standard, and I agree that flieee-single-bit-field and flieee-double-bit-field could be sensible names when "flonum" is more loosely defined. In Chez Scheme, though, a flonum is defined to be an IEEE 64-bit floating-point number, so there's no ambiguity in flbit-field. Also, the usefulness of this function seems tied to performance characteristics of a specific implementation, so I'm not sure it would be a great candidate for a standard. My preference would be to stick with the more obvious name flbit-field for Chez Scheme, but I don't feel too strongly about this if others would prefer a longer name.

The R6RS standard way to achieve what flbit-field does would be to create a bytevector holding a single flonum and then extracting the bits. This is likely non-optimised on most implementations (because an extra heap object is allocated). Thus, for almost all implementations, a specialised flbit-field can be implemented more efficiently.

If it is useful for external code, a portable feature would even be better.

The root problem is, of course, that one does not simply want to cast a flonum into an exact integer (to do bitwise arithmetic with that one) because 64-bits are typically more than the fixnum range (and thus would produce an allocation again) so one needs operations acting directly on flonums/inexact reals.

In any case, the name flbit-field probably wouldn't clash with a future standard because that would have to include "ieee-single" and "ieee-double" for consistency.

PS How is the endianness handled in your operation?

@mflatt
Copy link
Contributor Author

mflatt commented Oct 28, 2024

PS How is the endianness handled in your operation?

Like bitwise-bit-field, there's no question of endianness. In the implementation, a flonum's value is sitting in a floating-point register, that register's bits are transferred to an integer register (with the bit order intact, so that the sign bit is still the high bit, for example), and bits are then accessed from the integer register.

@mnieper
Copy link
Contributor

mnieper commented Oct 28, 2024

Like bitwise-bit-field, there's no question of endianness. In the implementation, a flonum's value is sitting in a floating-point register, that register's bits are transferred to an integer register (with the bit order intact, so that the sign bit is still the high bit, for example), and bits are then accessed from the integer register.

Ah, that was my fallacy. It is up to the flbit-field procedure to do the conversion in case on some supported architecture the endianness of the double and integer format does not coincide, so the user won't notice.

csug/numeric.stex Outdated Show resolved Hide resolved
@mflatt mflatt merged commit 95ee804 into cisco:main Oct 30, 2024
16 checks passed
@LiberalArtist
Copy link
Contributor

By coincidence, I was looking for something like this last week while I was contemplating the WASM generic numeric operation fcopysign, which corresponds to the concrete instructions f32.copysign and f64.copysign. It is supposed to look inside even the bit pattern of a NaN: I wrote a little more here. (I'm still not sure why this is a useful instruction to have.)

I used an intermediate bytevector (from Racket), but I noticed that Chez Scheme provides decode-float. I think flbit-field would make it possible to replace the C implementation with Scheme, if that seemed like a good idea:

ChezScheme/c/prim5.c

Lines 319 to 322 in 95ee804

static ptr s_decode_float(ptr x) {
require(Sflonump(x),"decode-float","~s is not a float",x);
return S_decode_float(FLODAT(x));
}

ChezScheme/c/number.c

Lines 1284 to 1321 in 95ee804

ptr S_decode_float(double d) {
union dxunion {
double d;
struct dblflt x;
} dx;
IBOOL s; INT e; U64 m;
ptr x, p;
/* pick apart the fields */
dx.d = d;
s = dx.x.sign;
e = dx.x.e;
m = (U64)dx.x.m1 << 48 | (U64)dx.x.m2 << 32 | (U64)dx.x.m3 << 16 | (U64)dx.x.m4;
if (e != 0) {
e = e - bias - bitstoright;
m |= hidden_bit;
} else if (m != 0) {
/* denormalized */
e = 1 - bias - bitstoright;
}
/* compute significand */
if (m <= most_positive_fixnum)
x = FIX((uptr)m);
else {
iptr xl;
x = FIX(0);
U64_TO_BIGNUM(get_thread_context(), x, m, &xl)
SETBIGLENANDSIGN(x, xl, 0);
}
/* construct return vector */
p = S_vector(3);
INITVECTIT(p,0) = x;
INITVECTIT(p, 1) = FIX(e);
INITVECTIT(p, 2) = s ? FIX(-1) : FIX(1);
return p;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants