Turn int to IEEE 754, extract exponent, and add 1 to exponent - c

Problem
I need to multiply a number without using * or + operator or other libs, only binary logic
To multiply a number by two using the IEEE norm, you add one to the exponent, for example:
12 = 1 10000010 100000(...)
So the exponent is: 10000010 (130)
If I want to multiply it by 2, I just add 1 to it and it becomes 10000011 (131).
Question
If I get a float, how do I turn it into, binary, then IEEE norm? Example:
8.0 = 1000.0 in IEEE I need it to have only one number on the left side, so 1.000 * 2^3. Then how do I add one so I multiply it by 2?
I need to get a float, ie. 6.5
Turn it to binary 110.1
Then to IEEE 754 0 10000001 101000(...)
Extract the exponent 10000001
Add one to it 10000010
Return it to IEEE 754 0 10000010 101000(...)
Then back to float 13

Given that the C implementation is known to use IEEE-754 basic 32-bit binary floating-point for its float type, the following code shows how to take apart the bits that represent a float, adjust the exponent, and reassemble the bits. Only simple multiplications involving normal numbers are handled.
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main(void)
{
float f = 6.125;
// Copy the bits that represent the float f into a 32-bit integer.
uint32_t u;
assert(sizeof f == sizeof u);
memcpy(&u, &f, sizeof u);
// Extract the sign, exponent, and significand fields.
uint32_t sign = u >> 31;
uint32_t exponent = (u >> 23) & 0xff;
uint32_t significand = u & 0x7fffff;
// Assert the exponent field is in the normal range and will remain so.
assert(0 < exponent && exponent < 254);
// Increment the exponent.
++exponent;
// Reassemble the bits and copy them back into f.
u = sign << 31 | exponent << 23 | significand;
memcpy(&f, &u, sizeof f);
// Display the result.
printf("%g\n", f);
}

Maybe not exactly what you are looking for, but C has a library function ldexp which does exactly what you need:
double x = 6.5;
x = ldexp(x, 1); // now x is 13

Maybe unions is the tool you need.
#include<iostream>
union fb {
float f;
struct b_s {
unsigned int sign :1;
unsigned int mant :22;
unsigned int exp :8;
} b;
};
fb num;
int main() {
num.f = 3.1415;
num.b.exp++;
std::cout << num.f << std::endl;
return 0;
}

Related

How can I obtain a float value from a double, with mantissa?

I'm sorry if I can't explain correctly, but my english management is so bad.
Well, the question is: I have a double var, and I cast this var to float, because I need to send exclusively 4 bytes, not 8. This isn't work for me, so I decide to calculate the value directly from IEEE754 standard.
I have this code:
union DoubleNumberIEEE754{
struct{
uint64_t mantissa : 52;
uint64_t exponent : 11;
uint64_t sign : 1;
}raw;
double d;
char c[8];
}dnumber;
floatval = (pow((-1), dnumber.raw.sign) * (1 + dnumber.raw.mantissa) * pow(2, (dnumber.raw.exponent - 1023)));
With these code, I can't obtain the correct value.
I am watching the header from linux to see the correct order of components, but I don't know if this code is correct.
I am skeptical that the double-to-float conversion is broken, but, assuming it is:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Create a mask of n low bits, for n from 0 to 63.
#define Mask(n) (((uint64_t) 1 << (n)) - 1)
/* This routine converts float values to double values:
float and double must be IEEE-754 binary32 and binary64, respectively.
The payloads of NaNs are not preserved, and only a quiet NaN is
returned.
The double is represented to the nearest value in float, with ties
rounded to the float with the even low bit in the significand.
We assume a standard C conversion from double to float is broken for
unknown reasons but that a converstion from a representable uint32_t to a
float works.
*/
static float ConvertDoubleToFloat(double x)
{
// Copy the double into a uint64_t so we can access its representation.
uint64_t u;
memcpy(&u, &x, sizeof u);
// Extract the fields from the representation of a double.
int SignCode = u >> 63;
int ExponentCode = u >> 52 & Mask(11);
uint64_t SignificandCode = u & Mask(52);
/* Convert the fields to their represented values.
The sign code merely encodes - or +.
The exponent code is biased by 1023 from the actual exponent.
The significand code represents the portion of the significand
after the radix point. However, since there is some problem
converting float to double, we will maintain it with an integer
type, scaled by 2**52 from its represented value.
The exponent code also represents the portion of the significand
before the radix point -- 1 if the exponent is non-zero, 0 if the
exponent is zero. We include that in the significand, scaled by
2**52.
*/
float Sign = SignCode ? -1 : +1;
int Exponent = ExponentCode - 1023;
uint64_t ScaledSignificand =
(ExponentCode ? ((uint64_t) 1 << 52) : 0) + SignificandCode;
// Handle NaNs and infinities.
if (ExponentCode == Mask(11))
return Sign * (SignificandCode == 0 ? INFINITY : NAN);
/* Round the significand:
If Exponent < -150, all bits of the significand are below 1/2 ULP
of the least positive float, so they round to zero.
If -150 <= Exponent < -126, only bits of the significand
corresponding to exponent -149 remain in the significand, so we
shift accordingly and round the residue.
Otherwise, the top 24 bits of the significand remain in the
significand (except when there is overflow to infinity), so we
shift accordingly and round the residue.
Note that the scaling in the new significand is 2**23 instead of 2**52,
since we are shifting it for the float format.
*/
uint32_t NewScaledSignificand;
if (Exponent < -150)
NewScaledSignificand = 0;
else
{
unsigned Shift = 53 - (Exponent < -126 ? Exponent - -150 : 24);
NewScaledSignificand = ScaledSignificand >> Shift;
// Clamp the exponent for subnormals.
if (Exponent < -126)
Exponent = -126;
// Examine the residue being lost and round accordingly.
uint64_t Residue = ScaledSignificand - ((uint64_t) NewScaledSignificand << Shift);
uint64_t Half = (uint64_t) 1 << Shift-1;
// If the residue is greater than 1/2 ULP, round up (in magnitude).
if (Half < Residue)
NewScaledSignificand += 1;
/* If the residue is 1/2 ULP, round 0.1 to 0 and 1.1 to 10.0 (these
numerals are binary with "." marking the ULP position).
*/
else if (Half == Residue)
NewScaledSignificand += NewScaledSignificand & 1;
/* Otherwise, the residue is less than 1/2, and we have already
rounded down, in the shift.
*/
}
// Combine the components, including removing the significand scaling.
return Sign * ldexpf(NewScaledSignificand, Exponent-23);
}
static void TestOneSign(double x)
{
float Expected = x;
float Observed = ConvertDoubleToFloat(x);
if (Observed != Expected && !(isnan(Observed) && isnan(Expected)))
{
printf("Error, %a -> %a, but expected %a.\n",
x, Observed, Expected);
exit(EXIT_FAILURE);
}
}
static void Test(double x)
{
TestOneSign(+x);
TestOneSign(-x);
}
int main(void)
{
for (int e = -1024; e < 1024; ++e)
{
Test(ldexp(0x1.0p0, e));
Test(ldexp(0x1.4p0, e));
Test(ldexp(0x1.8p0, e));
Test(ldexp(0x1.cp0, e));
Test(ldexp(0x1.5555540p0, e));
Test(ldexp(0x1.5555548p0, e));
Test(ldexp(0x1.5555550p0, e));
Test(ldexp(0x1.5555558p0, e));
Test(ldexp(0x1.5555560p0, e));
Test(ldexp(0x1.5555568p0, e));
Test(ldexp(0x1.5555570p0, e));
Test(ldexp(0x1.5555578p0, e));
}
Test(3.14);
Test(0);
Test(INFINITY);
Test(NAN);
Test(1/3.);
Test(0x1p128);
Test(0x1p128 - 0x1p104);
Test(0x1p128 - 0x.9p104);
Test(0x1p128 - 0x.8p104);
Test(0x1p128 - 0x.7p104);
}

Getting the mantissa (of a float) of either an unsigned int or a float (C)

So, i am trying to program a function which prints a given float number (n) in its (mantissa * 2^exponent) format. I was abled to get the sign and the exponent, but not the mantissa (whichever the number is, mantissa is always equal to 0.000000). What I have is:
unsigned int num = *(unsigned*)&n;
unsigned int m = num & 0x007fffff;
mantissa = *(float*)&m;
Any ideas of what the problem might be?
The C library includes a function that does this exact task, frexp:
int expon;
float mant = frexpf(n, &expon);
printf("%g = %g * 2^%d\n", n, mant, expon);
Another way to do it is with log2f and exp2f:
if (n == 0) {
mant = 0;
expon = 0;
} else {
expon = floorf(log2f(fabsf(n)));
mant = n * exp2f(-expon);
}
These two techniques are likely to give different results for the same input. For instance, on my computer the frexpf technique describes 4 as 0.5 × 23 but the log2f technique describes 4 as 1 × 22. Both are correct, mathematically speaking. Also, frexp will give you the exact bits of the mantissa, whereas log2f and exp2f will probably round off the last bit or two.
You should know that *(unsigned *)&n and *(float *)&m violate the rule against "type punning" and have undefined behavior. If you want to get the integer with the same bit representation as a float, or vice versa, use a union:
union { uint32_t i; float f; } u;
u.f = n;
num = u.i;
(Note: This use of unions is well-defined in C since roughly 2003, but, due to the C++ committee's long-standing habit of not paying sufficient attention to changes going into C, it is not officially well-defined in C++.)
You should also know IEEE floating-point numbers use "biased" exponents. When you initialize a float variable's mantissa field but leave its exponent field at zero, that gives you the representation of a number with a large negative exponent: in other words, a number so small that printf("%f", n) will print it as zero. Whenever printf("%f", variable) prints zero, change %f to %g or %a and rerun the program before assuming that variable actually is zero.
You are stripping off the bits of the exponent, leaving 0. An exponent of 0 is special, it means the number is denormalized and is quite small, at the very bottom of the range of representable numbers. I think you'd find if you looked closely that your result isn't quite exactly zero, just so small that you have trouble telling the difference.
To get a reasonable number for the mantissa, you need to put an appropriate exponent back in. If you want a mantissa in the range of 1.0 to 2.0, you need an exponent of 0, but adding the bias means you really need an exponent of 127.
unsigned int m = (num & 0x007fffff) | (127 << 23);
mantissa = *(float*)&m;
If you'd rather have a fully integer mantissa you need an exponent of 23, biased it becomes 150.
unsigned int m = (num & 0x007fffff) | ((23+127) << 23);
mantissa = *(float*)&m;
In addition to zwol's remarks: if you want to do it yourself you have to acquire some knowledge about the innards of an IEEE-754 float. Once you have done so you can write something like
#include <stdlib.h>
#include <stdio.h>
#include <math.h> // for testing only
typedef union {
float value;
unsigned int bits; // assuming 32 bit large ints (better: uint32_t)
} ieee_754_float;
// clang -g3 -O3 -W -Wall -Wextra -Wpedantic -Weverything -std=c11 -o testthewest testthewest.c -lm
int main(int argc, char **argv)
{
unsigned int m, num;
int exp; // the exponent can be negative
float n, mantissa;
ieee_754_float uf;
// neither checks nor balances included!
if (argc == 2) {
n = atof(argv[1]);
} else {
exit(EXIT_FAILURE);
}
uf.value = n;
num = uf.bits;
m = num & 0x807fffff; // extract mantissa (i.e.: get rid of sign bit and exponent)
num = num & 0x7fffffff; // full number without sign bit
exp = (num >> 23) - 126; // extract exponent and subtract bias
m |= 0x3f000000; // normalize mantissa (add bias)
uf.bits = m;
mantissa = uf.value;
printf("n = %g, mantissa = %g, exp = %d, check %g\n", n, mantissa, exp, mantissa * powf(2, exp));
exit(EXIT_SUCCESS);
}
Note: the code above is one of the quick&dirty(tm) species and is not meant for production. It also lacks handling for subnormal (denormal) numbers, a thing you must include. Hint: multiply the mantissa with a large power of two (e.g.: 2^25 or in that ballpark) and adjust the exponent accordingly (if you took the value of my example subtract 25).

Bit shifting for fixed point arithmetic on float numbers in C

i wrote the following test code to check fixed point arithmetic and bit shifting.
void main(){
float x = 2;
float y = 3;
float z = 1;
unsigned int * px = (unsigned int *) (& x);
unsigned int * py = (unsigned int *) (& y);
unsigned int * pz = (unsigned int *) (& z);
*px <<= 1;
*py <<= 1;
*pz <<= 1;
*pz =*px + *py;
*px >>= 1;
*py >>= 1;
*pz >>= 1;
printf("%f %f %f\n",x,y,z);
}
The result is
2.000000 3.000000 0.000000
Why is the last number 0? I was expecting to see a 5.000000
I want to use some kind of fixed point arithmetic to bypass the use of floating point numbers on an image processing application. Which is the best/easiest/most efficient way to turn my floating point arrays into integers? Is the above "tricking the compiler" a robust workaround? Any suggestions?
If you want to use fixed point, dont use type 'float' or 'double' because them has internal structure. Floats and Doubles have specific bit for sign; some bits for exponent, some for mantissa (take a look on color image here); so they inherently are floating point.
You should either program fixed point by hand storing data in integer type, or use some fixed-point library (or language extension).
There is a description of Floating point extensions implemented in GCC: http://gcc.gnu.org/onlinedocs/gcc/Fixed_002dPoint.html
There is some MACRO-based manual implementation of fixed-point for C: http://www.eetimes.com/discussion/other/4024639/Fixed-point-math-in-C
What you are doing are cruelties to the numbers.
First, you assign values to float variables. How they are stored is system dependant, but normally, IEEE 754 format is used. So your variables internally look like
x = 2.0 = 1 * 2^1 : sign = 0, mantissa = 1, exponent = 1 -> 0 10000000 00000000000000000000000 = 0x40000000
y = 3.0 = 1.5 * 2^1 : sign = 0, mantissa = 1.5, exponent = 1 -> 0 10000000 10000000000000000000000 = 0x40400000
z = 1.0 = 1 * 2^0 : sign = 0, mantissa = 1, exponent = 0 -> 0 01111111 00000000000000000000000 = 0x3F800000
If you do some bit shiftng operations on these numbers, you mix up the borders between sign, exponent and mantissa and so anything can, may and will happen.
In your case:
your 2.0 becomes 0x80000000, resulting in -0.0,
your 3.0 becomes 0x80800000, resulting in -1.1754943508222875e-38,
your 1.0 becomes 0x7F000000, resulting in 1.7014118346046923e+38.
The latter you lose by adding -0.0 and -1.1754943508222875e-38, which becomes the latter, namely 0x80800000, which should be, after >>ing it by 1, 3.0 again. I don't know why it isn't, probably because I made a mistake here.
What stays is that you cannot do bit-shifting on floats an expect a reliable result.
I would consider converting them to integer or other fixed-point on the ARM and sending them over the line as they are.
It's probable that your compiler uses IEEE 754 format for floats, which in bit terms, looks like this:
SEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFF
^ bit 31 ^ bit 0
S is the sign bit s = 1 implies the number is negative.
E bits are the exponent. There are 8 exponent bits giving a range of 0 - 255 but the exponent is biased - you need to subtract 127 to get the true exponent.
F bits are the fraction part, however, you need to imagine an invisible 1 on the front so the fraction is always 1.something and all you see are the binary fraction digits.
The number 2 is 1 x 21 = 1 x 2128 - 127 so is encoded as
01000000000000000000000000000000
So if you use a bit shift to shift it right you get
10000000000000000000000000000000
which by convention is -0 in IEEE754, so rather than multiplying your number by 2 your shift has made it zero.
The number 3 is [1 + 0.5] x 2128 - 127
which is represented as
01000000010000000000000000000000
Shifting that left gives you
10000000100000000000000000000000
which is -1 x 2-126 or some very small number.
You can do the same for z, but you probably get the idea that shifting just screws up floating point numbers.
Fixed point doesn't work that way. What you want to do is something like this:
void main(){
// initing 8bit fixed point numbers
unsigned int x = 2 << 8;
unsigned int y = 3 << 8;
unsigned int z = 1 << 8;
// adding two numbers
unsigned int a = x + y;
// multiplying two numbers with fixed point adjustment
unsigned int b = (x * y) >> 8;
// use numbers
printf("%d %d\n", a >> 8, b >> 8);
}

How to do serialization of float numbers on network?

I found a piece of code to do the serialization of float numbers on network.
uint32_t htonf(float f)
{
uint32_t p;
uint32_t sign;
if (f < 0) { sign = 1; f = -f; }
else { sign = 0; }
p = ((((uint32_t)f)&0x7fff)<<16) | (sign<<31); // whole part and sign
p |= (uint32_t)(((f - (int)f) * 65536.0f))&0xffff; // fraction
return p;
}
Spec: The above code is sort of a naive implementation that stores a float in a 32-bit number. The high bit (31) is used to store the sign of the number ("1" means negative), and the next seven bits (30-16) are used to store the whole number portion of the float. Finally, the remaining bits (15-0) are used to store the fractional portion of the number.
The others are fine but I cannot figure out what this means. How does this get us the 15-0 bits? Why do we need the "*65536.0f"?
p |= (uint32_t)(((f - (int)f) * 65536.0f))&0xffff
Anyone can explain on this?
f - (int)f
gives you the fractional part of the number. You want to store this fraction in 16 bits, so think of it as a fraction with 2^16 as the denominator. The numerator is:
(f - (int)f) * 65536.0f)
The rest just uses bit shifting to pack it up into the right bits in the 32 bit number. Then that 32 bit int is serialized on the network like any other 32 bit int, and presumably the opposite of the above routine is used to re-create a floating point number.
You could use a union.
uint32_t htonf(float f)
{
union {
float f1;
uint32_t i1;
};
f1 = f;
return i1;
}

Converting double to float without relying on the FPU rounding mode

Does anyone have handy the snippets of code to convert an IEEE 754 double to the immediately inferior (resp. superior) float, without changing or assuming anything about the FPU's current rounding mode?
Note: this constraint probably implies not using the FPU at all. I expect the simplest way to do it in these conditions is to read the bits of the double in a 64-bit long and to work with that.
You can assume the endianness of your choice for simplicity, and that the double in question is available through the d field of the union below:
union double_bits
{
long i;
double d;
};
I would try to do it myself but I am certain I would introduce hard-to-notice bugs for denormalized or negative numbers.
I think the following works, but I will state my assumptions first:
floating-point numbers are stored in IEEE-754 format on your implementation,
No overflow,
You have nextafterf() available (it's specified in C99).
Also, most likely, this method is not very efficient.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[])
{
/* Change to non-zero for superior, otherwise inferior */
int superior = 0;
/* double value to convert */
double d = 0.1;
float f;
double tmp = d;
if (argc > 1)
d = strtod(argv[1], NULL);
/* First, get an approximation of the double value */
f = d;
/* Now, convert that back to double */
tmp = f;
/* Print the numbers. %a is C99 */
printf("Double: %.20f (%a)\n", d, d);
printf("Float: %.20f (%a)\n", f, f);
printf("tmp: %.20f (%a)\n", tmp, tmp);
if (superior) {
/* If we wanted superior, and got a smaller value,
get the next value */
if (tmp < d)
f = nextafterf(f, INFINITY);
} else {
if (tmp > d)
f = nextafterf(f, -INFINITY);
}
printf("converted: %.20f (%a)\n", f, f);
return 0;
}
On my machine, it prints:
Double: 0.10000000000000000555 (0x1.999999999999ap-4)
Float: 0.10000000149011611938 (0x1.99999ap-4)
tmp: 0.10000000149011611938 (0x1.99999ap-4)
converted: 0.09999999403953552246 (0x1.999998p-4)
The idea is that I am converting the double value to a float value—this could be less than or greater than the double value depending upon the rounding mode. When converted back to double, we can check if it is smaller or greater than the original value. Then, if the value of the float is not in the right direction, we look at the next float number from the converted number in the original number's direction.
To do this job more accurately than just re-combine mantissa and exponent bit's check this out:
http://www.mathworks.com/matlabcentral/fileexchange/23173
regards
I posted code to do this here: https://stackoverflow.com/q/19644895/364818 and copied it below for your convenience.
// d is IEEE double, but double is not natively supported.
static float ConvertDoubleToFloat(void* d)
{
unsigned long long x;
float f; // assumed to be IEEE float
unsigned long long sign ;
unsigned long long exponent;
unsigned long long mantissa;
memcpy(&x,d,8);
// IEEE binary64 format (unsupported)
sign = (x >> 63) & 1; // 1
exponent = ((x >> 52) & 0x7FF); // 11
mantissa = (x >> 0) & 0x000FFFFFFFFFFFFFULL; // 52
exponent -= 1023;
// IEEE binary32 format (supported)
exponent += 127; // rebase
exponent &= 0xFF;
mantissa >>= (52-23); // left justify
x = mantissa | (exponent << 23) | (sign << 31);
memcpy(&f,&x,4);
return f;
}

Resources