ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I just want to verify that if I shift a c/C++ variable to the left by 1 that it is still multiplying by 2 even if the variable is a float and regardless of implementation.
Click here to see the post LQ members have rated as the most helpful post in this thread.
But to answer the question, no, you cannot meaningfully bit-shift a float. As the above code demonstrates when you try to compile, an error is displayed:
Code:
error: invalid operands to binary << (have ‘float’ and ‘int’)
Further, if you try to "trick" the compiler into bit shifting a float (e.g. as demonstrated on this page) by using some casting, you are not guaranteed to get a "multiply by two" result.
Floats, and doubles, are stored in a special format as described in this wikipedia page. Specifically, the 32 bits used for a float are split into two groups: a significand and an exponent. A bit shift can potentially shift bits from the exponent group into the significand group or vice versa.
Right. However, at least C99 has functions ldexpf(), ldexp(), and ldexpl(), which do the same logical operation to a float, double, or long double (correspondingly). In other words,
Code:
double x, y;
int n;
y = ldexp(x, n); /* y = x * (1 << n) */
except it works for the full double range, n = -1021 .. 1022, and may be much faster than a multiplication on some architectures.
This is not a programming trick, though. The low-level instruction executed by the CPU is different for floating-point values than it is for integers. I am not certain, but it is possible some C++ compiler options map << for floating-point values to those instructions automatically. For compatibility, better use ldexp() function directly. (There are also corresponding inverse frexp() functions, which split any floating-point value to a normalized fraction ±[0.5, 1) and a power-of-two exponent.)
This is not a programming trick, though. The low-level instruction executed by the CPU is different for floating-point values than it is for integers. I am not certain, but it is possible some C++ compiler options map << for floating-point values to those instructions automatically. For compatibility, better use ldexp() function directly. (There are also corresponding inverse frexp() functions, which split any floating-point value to a normalized fraction ±[0.5, 1) and a power-of-two exponent.)
Using those functions incurs a dependence on -lm, also.
C++03 guarantees that << and >> are defined for "integral types" but not for "floating types", so it might not even compile in some cases. For example, Comeau doesn't compile the expression double a = .16 << 2;.
Kevin Barry
Last edited by ta0kira; 03-02-2012 at 09:45 AM.
Reason: grammar correction
Without prolonging this thread unnecessarily, I think I look at the original question a little differently than ta0kira and Nominal Animal.
My focus is on the OP's language that "if I shift a c/C++ variable to the left by 1" -- meaning that the OP's interest is to directly apply bit shifting to the variable(s).
My concern was not the perceived "multiply by 2" side effect of bit shifting. If the OP was looking for an efficient means of multiplying a value by a power of 2, that's fine. But bit-shifting is useful for more than math shortcuts. Indeed, a big part of my old job was using bit shifting to implement binary queues.
bit-shifting is useful for more than math shortcuts. Indeed, a big part of my old job was using bit shifting to implement binary queues.
Right. Also, many file formats (GIF, MPEG for example) treat data as a sequence of bits.
I assumed we are talking about multiplication by a power of two, not bit sequence manipulation.
For me, only unsigned integer types make any sense when handling bit sequences -- I mean, the part where you extract and shift the bits into more manageable units, or inversely pack units as a bit sequence.
In general, in C99, I use unsigned char for CHAR_BIT-bit bytes, or unsigned long for CHAR_BIT * sizeof (unsigned long) -bit words (typically most efficient handling unit, uses local endian byte order). This is either 32 bits or 64 bits in all current Linux architectures (ILP32 and LP64, respectively).
To convert to say floating-point types, it is usually more efficient to just construct the bit sequence in a suitable unsigned integer type (uint32_t for floats, uint64_t for doubles), then type-pun the value (via reinterpret_cast in C++). Conversion using ldexp()/frexp() is more general, but also much slower. It is much faster to determine the correct bit patterns at compile time, and not use floating-point at all.
Even signed integers have serious issues; shifting a signed integer down duplicates the high bit, whereas shifting an unsigned integer down inserts zero high bits. This means that (int)(-1) >> 1 == (int)(-1) in both C99 and C++.
I assumed we are talking about multiplication by a power of two, not bit sequence manipulation.
Correct. What I was inarticulate at explaining in my last reply (regarding that I "looked at" the question a little differently):
My impression was that you and ta0kira interpreted the question as though the "multiply by 2" effect was the OP's ultimate goal--that the bit shifting was a means to an end.
I interpreted the question as though the OP wanted to bit shift any variable. And as a consequence, use the "multiply by 2" as a mechanism to verify the shift or as an alternate method for shifting.
That's all I was getting at.
Though, as a side note, you reminded me of that old job a little more with the signed int shifting reference. The signed int shift was quite useful. We were simulating some hardware design interaction. The binary queues I mentioned were the square waves propagating through the simulated design. The signed ints were useful in modeling a "pull-up resistor" in the circuit. The unsigneds were useful for pull-downs.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.