Re: converting an unsigned 64 bit in a FPU double



Terje Mathisen <spamtrap@xxxxxxxxxx> writes:
Phil Carmody wrote:
jacob navia <spamtrap@xxxxxxxxxx> writes:
Hi

Suppose following:

You got in some general 64 bit reg (say rax) an unsigned
number and you want to convert it to long double
(FPU 80 bits)
For most questions like this, about tiny and common primitives, the
answer is simply to see how gcc does it, and do that.

The best I thought can be done is:
(using gcc notation)

push $0
push rax
fldq (%rsp)
That expects to load a floating point value. You don't have a
floating point value.
To load a _signed_ integer you use the FILD* instructions
If your unsigned value is larger than 63 bits, then you'll
need to fix up (by subtracting 2^64).

Yeah, unsigned 64-bit is somewhat troublesome. :-(

I used to use uint64_t for a lot of my prime number work,
working modulo small primes. Annoyances everywhere.
Eventually realised that balanced representation wasn't
just more efficient from a Int<->FPU perspective (of which
there was plenty), but had several other benefits,
including _increased_ ranges of numbers that I could work
with, sometimes. int64_t almost everywhere now.

The easiest (and by far most portable!) way I've found is to simply
bias the input, then adjust the result, i.e.:

extended uint64_to_extended(uint64_t u64)
{
u64 -= ((uint64_t) 1) << 63; // Bias the input

You don't need the carry, so you can just toggle the
63rd bit as a logical operation rather than an arithmetic
one.

extended e = (extended) ((int64_t) u64); // Convert to fp
e += 32768.0*65536.0*65536.0*65536.0; // Un-bias the result
return e;
}

If, otoh, maximally large input values are quite rare, then it will be
much faster to use a test/branch to handle those values:

extended uint64_to_extended(uint64_t u64)
{
int64_t i64 = (int64_t) u64;
extended e = (extended) i64; // Convert to fp
// Check if the input was >= 2^63
if (i64 < 0) { // Top/Sign bit set?
e += 65536.0*65536.0*65536.0*65536.0;
}
return e;
}

For reference, GCC (4.2) compiles that into _exactly_
the same code as
extended uint64_to_extended(uint64_t u64) { return(extended)u64; }

Phil
--
Dear aunt, let's set so double the killer delete select all.
-- Microsoft voice recognition live demonstration

.



Relevant Pages

  • Re: converting an unsigned 64 bit in a FPU double
    ... (using gcc notation) ... That expects to load a floating point value. ... extended uint64_to_extended(uint64_t u64) ...
    (comp.lang.asm.x86)
  • Re: GCC front-end for FORTH?
    ... gcc uses this a great deal: ... Yes, but you have to get that global pointer, and that's through a ... PC-relative load in most cases. ... Gforth's examination of this primitive says: ...
    (comp.lang.forth)
  • Re: key steps to get c-file debugging info into AVRStudio 4
    ... >I got to that while porting and thought it seemed suspect. ... >deciding factor for me - to stick with GCC for a bit longer to see if I ... >able to browse your help even if it does not load. ... >convert me to ICCAVR. ...
    (comp.arch.embedded)
  • Re: modload - weird behavior
    ... modload is giving strange error while trying to load a module. ... > Following is the source code of module ... > int _init ... > I compiled it using gcc: ...
    (comp.unix.solaris)
  • Re: Faulty claims for lcc-win32
    ... Or will it break some kind of CPU specific cache boundary? ... He said that gcc produced even smaller ones and changed ... executables, others begun saying to me that small programs are slower ... I told them that that is not the case, small programs load ...
    (comp.lang.c)