"Shifting" floating point numbers

W

woessner

Does anyone know of a fast way to multiply floating point numbers by
powers of two? Conceptually, all you need to do is add to the
mantissa. But can I write C code (or x86 assembly) to accomplish this
without a full-blown multiply?

For example, I'd like to be able to do the following very quickly:

double x;
double y;

x = 42.13;
y = (1 << 9) * x;

Thanks in advance,
Bill
 
S

santosh

Does anyone know of a fast way to multiply floating point numbers by
powers of two? Conceptually, all you need to do is add to the
mantissa. But can I write C code (or x86 assembly) to accomplish this
without a full-blown multiply?

For example, I'd like to be able to do the following very quickly:

double x;
double y;

x = 42.13;
y = (1 << 9) * x;

If you know the floating point representation of your implementation
and underlying hardware, you can copy the float value to an unsiged
long variable, shift the appropriate bits and copy the value back to
the float variable. All this implies that you'll have to know details
about your implementation and thus risk losing some portability.

These days, FPU's are quite fast, so a direct multiply on the float
should be efficient enough unless you're code is time critical.
 
S

Skarmander

Does anyone know of a fast way to multiply floating point numbers by
powers of two? Conceptually, all you need to do is add to the
mantissa. But can I write C code (or x86 assembly) to accomplish this
without a full-blown multiply?
My advice: don't bother. The chance that you'll beat the combination of FPU
and compiler is small, and a trick like this tends to break down when you
least expect it.

For example, if you want to do this the right way, you have to deal with the
infinities, denormalized numbers, NaNs and last but not least, zero. But of
course you can't, since that would make your code far too slow.
For example, I'd like to be able to do the following very quickly:

double x;
double y;

x = 42.13;
y = (1 << 9) * x;
Verify that you really need to do this faster than you're doing it now
first. Then see if there's some way to avoid doing the multiplication
altogether (at least in tight loops) by changing the way you handle your
data. Finally, if all these options are exhausted, you'd best go with x86
assembler and read up on the format of double precision numbers. Try
comp.lang.asm.x86. When you're at this point, C (even nonportable C) is
unlikely to help you enough.

S.
 
E

Eric Sosman

Does anyone know of a fast way to multiply floating point numbers by
powers of two? Conceptually, all you need to do is add to the
mantissa.

ITYM "add the exponent."
But can I write C code (or x86 assembly) to accomplish this
without a full-blown multiply?

For example, I'd like to be able to do the following very quickly:

double x;
double y;

x = 42.13;
y = (1 << 9) * x;

#include <math.h>
...
y = ldexp(x, 9);

No guarantees about relative speed, though: You'll
need to measure on the platform(s) of interest.
 
P

Pierre Maurette

(e-mail address removed), le 21/03/2006 a écrit :
Does anyone know of a fast way to multiply floating point numbers by
powers of two? Conceptually, all you need to do is add to the
mantissa.
Mantissa ? Exponent, no ?
But can I write C code (or x86 assembly) to accomplish this
without a full-blown multiply?
[I consider Intel FPU, double / real8]
A problem is in the position of the exponent in the double. From bit 52
to bit 62. You can't use this way in order to have faster code, just
for fun.

In assembly, you have two ways:

- FIMUL, multiply a FP data by an integer.

- FSCALE, that do just what you want, multiply very quickly by a power
of 2 ;-) You need just to have the power (9, not 2^9 !) in ST(1) and do
FSCALE.
 
K

Keith Thompson

Pierre Maurette said:
(e-mail address removed), le 21/03/2006 a écrit :
Does anyone know of a fast way to multiply floating point numbers by
powers of two? Conceptually, all you need to do is add to the
mantissa.
Mantissa ? Exponent, no ?
But can I write C code (or x86 assembly) to accomplish this
without a full-blown multiply?
[I consider Intel FPU, double / real8]
A problem is in the position of the exponent in the double. From bit
52 to bit 62. You can't use this way in order to have faster code,
just for fun.

In assembly, you have two ways:

- FIMUL, multiply a FP data by an integer.

- FSCALE, that do just what you want, multiply very quickly by a power
of 2 ;-) You need just to have the power (9, not 2^9 !) in ST(1) and
do FSCALE.

Please don't post system-specific answers like this here. Most of us
have no way of knowing whether your description is accurate. I make
mistakes every now and then; when I make them in a forum full of
experts on what I'm talking about, they'll be corrected.

And, of course, it's off-topic. There are newsgroups where such
things are topical; comp.lang.asm.x86 is probably one of them.
 
P

Pierre Maurette

Keith Thompson, le 21/03/2006 a écrit :
[...]
And, of course, it's off-topic. There are newsgroups where such
things are topical; comp.lang.asm.x86 is probably one of them.
I agree your remark. But its was an answer to an off-topic question.
 
K

Keith Thompson

Does anyone know of a fast way to multiply floating point numbers by
powers of two? Conceptually, all you need to do is add to the
mantissa. But can I write C code (or x86 assembly) to accomplish this
without a full-blown multiply?

For example, I'd like to be able to do the following very quickly:

double x;
double y;

x = 42.13;
y = (1 << 9) * x;

Compile the code with whatever optimization options are appropriate,
and look at the assembly language. If your compiler generates code
that uses something other than (and presumably faster than) a
floating-point multiply, then you're all set; there's no need to do
source-level optimization if the compiler will do it for you. If the
compiler emits an ordinary floating-point multiply instruction, then
it may mean that that's the best way to do the multiplication.

It's also possible that you can optimize this better than your
compiler can, but that's not the way to bet (unless you've actually
measured it).

And always remember the Rules of Optimization:

Rule 1: Don't do it.
Rule 2 (for experts only): Don't do it yet.
 
J

Jordan Abel

- FSCALE, that do just what you want, multiply very quickly by a power
of 2 ;-) You need just to have the power (9, not 2^9 !) in ST(1) and do
FSCALE.

This instruction may be available to C as the "scalbn" function (and if
not, scalbn will be a software implementation that does the same thing),
and I suspect this is exactly what he wants.

C99 only, of course.

Here's my system's implementation of it for i387

RCSID("$FreeBSD: src/lib/msun/i387/s_scalbn.S,v 1.7 1999/08/28 00:06:13 peter Exp $")

ENTRY(scalbn)
fildl 12(%esp)
fldl 4(%esp)
fscale
fstp %st(1)
ret
 
J

Jordan Abel

Keith Thompson, le 21/03/2006 a écrit :
[...]
And, of course, it's off-topic. There are newsgroups where such
things are topical; comp.lang.asm.x86 is probably one of them.
I agree your remark. But its was an answer to an off-topic question.

Not really. scalbn() [and its friends] are the on-topic answer.
 
J

Jordan Abel

Does anyone know of a fast way to multiply floating point numbers by
powers of two? Conceptually, all you need to do is add to the
mantissa. But can I write C code (or x86 assembly) to accomplish this
without a full-blown multiply?

For example, I'd like to be able to do the following very quickly:

double x;
double y;

x = 42.13;
y = (1 << 9) * x;

Thanks in advance,
Bill

y = scalbn(x,9);

Everyone else thinks you're off-topic because no-one else knows about
this function, apparently.
 
E

Eric Sosman

Jordan Abel wrote On 03/21/06 15:51,:
y = scalbn(x,9);

ITYM:

#if FLT_RADIX == 2
y = scalbn(x, 9);
#else
y = ???;
#endif

I've already posted a candidate for "???", one that
eliminates the dependency on C99 and perhaps even
obviates the preprocessor gunk ...
 
K

Keith Thompson

Pierre Maurette said:
Keith Thompson, le 21/03/2006 a écrit :
[...]
And, of course, it's off-topic. There are newsgroups where such
things are topical; comp.lang.asm.x86 is probably one of them.
I agree your remark. But its was an answer to an off-topic question.

The question was partly off-topic. But the solution is simple: don't
try to answer off-topic questions; instead, redirect the poster to an
appropriate forum. (I sometimes offer a small system-specific hint
while doing so, but it's usually no more than a pointer to the
answer.)
 
P

P.J. Plauger

ITYM "add the exponent."


#include <math.h>
...
y = ldexp(x, 9);

No guarantees about relative speed, though: You'll
need to measure on the platform(s) of interest.

Before it gets lost in all the noise, this is the right answer.
And it's been in the C Standard since C89.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
J

Jordan Abel

Before it gets lost in all the noise, this is the right answer.
And it's been in the C Standard since C89.

I thought that ldexp set the exponent to the number given, i.e. the new
exponent would be 9 regardless of the current exponent (i.e. 42.13's
exponent is already six) - why is it called "ldexp" (i thought it stood
for "load exponent", which only makes sense with my version, not the
actual function)
 
K

Keith Thompson

Jordan Abel said:
I thought that ldexp set the exponent to the number given, i.e. the new
exponent would be 9 regardless of the current exponent (i.e. 42.13's
exponent is already six) - why is it called "ldexp" (i thought it stood
for "load exponent", which only makes sense with my version, not the
actual function)

The standard's description is:

The ldexp functions multiply a floating-point number by an
integral power of 2. A range error may occur.

Returns
The ldexp functions return x * 2**exp.

(equation translated to ASCII).
 
D

Dik T. Winter

> Does anyone know of a fast way to multiply floating point numbers by
> powers of two? Conceptually, all you need to do is add to the
> mantissa. But can I write C code (or x86 assembly) to accomplish this
> without a full-blown multiply?
>
> For example, I'd like to be able to do the following very quickly:
>
> double x;
> double y;
>
> x = 42.13;
> y = (1 << 9) * x;

With IEEE floating point shifting the mantissa will not accomplish what
you want. For instance, shifting the mantissa of 1.0 by any number of
bits will leave the value 1.0 because the mantissa (as a stored value)
is 0; there is an hidden (not stored) bit. When you want to multiply
by 2 you need to increment the exponent by 1.
 
R

Robin Haigh

Does anyone know of a fast way to multiply floating point numbers by
powers of two? Conceptually, all you need to do is add to the
mantissa. But can I write C code (or x86 assembly) to accomplish this
without a full-blown multiply?

For example, I'd like to be able to do the following very quickly:

double x;
double y;

x = 42.13;
y = (1 << 9) * x;


Not disagreeing with the wise words of others, but just for interest's sake
this non-portable one-liner seems to work if you stay away from the edges


#include <stdio.h>
int main (void) {

double x = 42.13;
double y;
int power = 9;

/* assuming 4-byte longs */

y = x;
((unsigned long *)&y)[1] += power << 20; /* IEEE little-endian */

/* (change [1] to [0] for big-endian) */

printf("%f\n", y);
return 0;
}


(For language lawyers, there are some questions about whether this code is
undefined behaviour, whether it still is in the equivalent using a union, or
if y is declared volatile (answers may be different in C89 and C99))
 
J

Jordan Abel

Does anyone know of a fast way to multiply floating point numbers by
powers of two? Conceptually, all you need to do is add to the
mantissa. But can I write C code (or x86 assembly) to accomplish this
without a full-blown multiply?

For example, I'd like to be able to do the following very quickly:

double x;
double y;

x = 42.13;
y = (1 << 9) * x;


Not disagreeing with the wise words of others, but just for interest's sake
this non-portable one-liner seems to work if you stay away from the edges


#include <stdio.h>
int main (void) {

double x = 42.13;
double y;
int power = 9;

/* assuming 4-byte longs */

y = x;
((unsigned long *)&y)[1] += power << 20; /* IEEE little-endian */

/* (change [1] to [0] for big-endian) */

printf("%f\n", y);
return 0;
}


(For language lawyers, there are some questions about whether this code is
undefined behaviour,
yes.

whether it still is in the equivalent using a union,
yes.

or if y is declared volatile

and yes.
(answers may be different in C89 and
C99))

no.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top