# how do I get the mantissa, sign, etc

So I have to write this code that will extract the mantissa, sign, and exponent from a floating point number. I know how to do this basically. I have a extract.h file and an extract.c file where the code is located and extract.h is just like the template (interface as if you say in java). In the extract.h file I have:

if defined(MACHINE32)

elif defined(MACHINE64)

but I am confused of what to put inside these statements so that I can use the same code twice to do this.

here's my code:

it works for a 32 bit machine, but what if it's 64bit?? can someone give me suggestions?
``````void getSignMantissaExponent(float number, int* sign, unsigned int* mantissa, int* exponent){
int* second = (int*) &number;
*sign = (*second) & 0x80000000;
*sign = *sign >> 31;

if (*sign == 0)
*sign = 1;
else
*sign = -1;

*exponent = (*second) & 0x7F800000;
*exponent = *exponent >> 23;
*exponent = *exponent - 127;

*mantissa = (*second) & 0x7FFFFF;
*mantissa = *mantissa | 0x800000;
}
``````
Infinity08

First of all, be aware that you're depending on how your system implements floating point values. Just because it runs on your system does not mean it will run on a different system.
You're assuming that the float is a single precision IEEE 754 floating point number. It's commonly used, but not all systems use it.

You're also depending on the fact that a float is the same size as an int (4 bytes in this case).

Verify the size of a float using sizeof(float), and base yourself on that, NOT the word size of the machine.

If on a 64bit machine you find that sizeof(float) == 8, then you could assume that you're dealing with a double precision IEEE 754 floating point number which has :

sign : 1 bit
exponent : 11 bits
mantissa : 52 bits
Also, take a look at the defines in the standard <float.h> header - they can help you figure out what the representation of the float is ...

http://www.cplusplus.com/reference/clibrary/cfloat/
You might consider calling frexp function instead:

float y = 0.;
float x = 16.4;
int n = 0;

y = (float)frexp( x, &n );
printf( "frexp( %f, &n ) = %f, n = %d\n", x, y, n );

It would print: frexp( 16.400000, &n ) = 0.512500, n = 5

The mantissa y returned is a float between 0.5 and 1. The n is an exponent so that x = y * 2^n. The return values of frexp are much better comparable as it is with two integers. Note, the frexp takes a double and returns a double. There is rarely a need to use float type instead of double nowadays.

TheRekz

well yes the 64 bit machine here uses the 8 bit representation as a floating point number, where
sign : 1 bit
exponent : 11 bits
mantissa : 52 bits

but my question is :

1. what do I have to put inside the if defined MACHINE32 and MACHINE 32
2. I should use the same function getSignMantissaExponent to do this, so therefore my thought here will be to put a different constatnt in MACHINE 32 and MACHINE 64 to do the masking differently. Is this right??

I don't want any other complicated solution,just based on my code above
If FLOAT32 and FLOAT64 indicate the size of a float (NOT the word size of the machine, because they're not necessarily the same), then you can do something like :

``````#ifdef FLOAT32
/* the code for 32bit floats */
#else
#ifdef FLOAT64
/* the code for 64bit floats */
#else
/* error !!! */
#endif
#endif``````
But again, you'll have to be careful with the size of an int on the system (whether it's able to hold the exponent and mantissa).

well ok this makes sense, but the ifdef is defined in the .h file, so therefore all there is just the method signature.. so what do we have to do?

yes the size of the system in the 64 bit machine that I am going to use, is using double precision and the 32 but is single precision..
>> but the ifdef is defined in the .h file

why ? You can put it in the file that contains the method implementation. Can you show both the .h and .c file ?

>> yes the size of the system in the 64 bit machine that I am going to use, is using double precision and the 32 but is single precision..

Ok. Fair enough. Just be aware that your code won't be completely portable.

the requirement of my assignment says so:

I have attached the .c and .h if you guys want to see:

``````/* extract module : code to help manipulate and debug floating point */

#ifndef EXTRACT_H_
#define EXTRACT_H_

#if defined(MACHINE32)

#elif defined(MACHINE64)

#else

#error 666

#endif /* MACHINE TYPE */

#include "sizes.h" /* User-defined defns for int_u8, int_8, int_u4, int_4 */

/* Extract the sign, mantissa and exponent from the given IEEE floating
** number.  The mantissa returned should have the hidden bit in the
** value, and the exponent should have the excess-127 already taken
** out.  The sign should just be -1 or 1.  In case the number is 0,
** the sign, mantisaa ad exponent should all be 0.   We will not
** handle denormalized numbers, infinities, just basic numbers
** that can be represented in IEEE floating point numbers.
*/
void getSignMantissaExponent(float number,
int_4* sign, int_u8* mantissa, int_4* exponent);

/* Given the sign, mantissa and exponent, print out the floating point
** number in binary:  it should show the hidden bit. The mantissa
** is printed in binary and the exponent is printed as a decimal
** number.  For example:
** 10  -> +1.01000000000000000000000e+3
** -10 -> -1.01000000000000000000000e+3
** .5  -> +1.00000000000000000000000e-1
** 0   ->  0.00000000000000000000000e+0
** Note that '0' prints a space out instead of + or - for the sign
*/
void binaryFloatPrint(int_4 sign, int_u8 mantissa, int_4 exponent);

#endif /* EXTRACT_H_ */``````

.c file, not yet completed and some code are still wrong:

#include "extract.h"
#include <stdio.h>

int DebugMode = 0;

void getSignMantissaExponent(float number, int_4* sign, int_u8* mantissa, int_4* exponent){
int_4 *second = (int_4*) &number;
int_u4 = temp_sign;
4 = temp_mantissa;
int_u
int exponent_result;

sign = (*second) & 0x80000000;
sign = sign >> 31;

exponent = (*second) & 0x7F800000;
exponent = exponent >> 23;
exponent_result = (int)exponent - 127;

mantissa = (*second) & 0x7FFFFF;
mantissa = mantissa | 0x800000;

printf("Sign bit is %u ", sign);
printf("Exponent is %d ", exponent_result);
printf("Mantissa is %x ", mantissa);
}

void binaryFloatPrint(int_4 sign, int_u8 mantissa, int_4 exponent){

}

>> the requirement of my assignment says so

Ok. So, what you want to do is put something there for the 2 cases that you can use in the .c file :

#if defined(MACHINE32)
/* <--- put something here */
#elif defined(MACHINE64)
/* <--- and here */
#else

#error 666

#endif /* MACHINE TYPE */

I suggest putting some #define's there that indicate the sizes of the float, the exponent and the mantissa ... what do you think ?

okay can I define a constant there that is the hexadecimal number to MASK with and a constant variable to shift the amount?
Sure, you can put there whatever you want.

Just identify the parts of the algorithm that are different between the 32bit and 64bit float versions, and make sure you can get those based on what you put in the #define's.

yes, this is what I've been thinking about.. I am just not sure now say that if I define something in the .h file how can I use it in the .c file, where the code is implemented. thanks
You have included the header file in the .c file using this :

#include "extract.h"

so, everything in the header file will be placed in the .c file.

oh okay I see.. I've got one more question though.. I have a function binaryFloatPoint that will print out the mantissa in binary and to do this I have to do it from the command line:

./extract --binary 10

I know how to extract the number 10 using the scanf, but how do I extract the --binary string from the command line??
when called like this :

extract --binary 10

the argv array will have three values (argc will be set to 3) :

argv[0] : "extract"
argv[1] : "--binary"
argv[2] : "10"
argv[3] : NULL

You can check first argument (take a look at strcmp) to see if it really is "--binary", and then you can use the second value.

will 10 hear read as a string or as an int?
It will be a string. argv is declared as an array of char* (C strings) :

int main(int argc, char *argv[])

so how do I get that as an int/floating point number if there's a fraction?? can I just use the scanf for the int??
>> can I just use the scanf for the int??

You can use a variant of scanf if you want : sscanf :

http://www.cplusplus.com/reference/clibrary/cstdio/sscanf.html

which works on strings.

Or you can go for atoi or strtol :

http://www.cplusplus.com/reference/clibrary/cstdlib/atoi.html
http://www.cplusplus.com/reference/clibrary/cstdlib/strtol.html

okay I see... I am actually doing this on a C not a C++ platform, so what does the scanf does?
>> okay I see... I am actually doing this on a C not a C++ platform

The functions I showed are pure C functions, don't worry.

I've got this weird thing in my C main code:

when ever I enter ./main .5 it doesn't take the argument .5 directly instead it goes to the next line and I have to enter it again so that it works.. here's the code:
``````int main()
{
float number;
scanf("%f", &number);

int_4 sign;
int_u8 mantissa;
int_4 exponent;

getSignMantissaExponent(number, &sign, &mantissa, &exponent);
printf("%6f has sign bit: %d mantissa:0x%x exponent: %d\n", number, sign, (unsigned int) mantissa, exponent);

return 0;
}``````
As I said before, you can't use scanf to read the arguments.

Here's a sample application that prints all arguments passed :

int main(int argc, char *argv[]) {
int i = 0;
for (i = 1; i < argc; ++i) {
printf("argument %d : %s\n", i, argv[i]);
}
return 0;
}

Try it out to see how it works.

no I don't want to get the string now, I am just testing the code first without the string --binary.. So I want to do ./main .5 and that .5 can be extracted, but when I enter ./main I got a new line instead..

okay I think I messed up in my assignment, can someone help me.. the link is at :

http://www.cs.arizona.edu/classes/cs352/spring08/programs/assign3.txt

I just dont understand where should I write the if defined (MACHINE32) etc
>> no I don't want to get the string now

What do you mean by that ?

If you want to pass arguments to you application, like this :

./main .5

Then you need to use code like I posted using argc and argv, because that's where the arguments are stored.

Try to compile the code I posted in my previous code, and run it, passing some arguments of your choice to it. See what happens.

>> okay I think I messed up in my assignment, can someone help me

That's what we've been doing all along ;)

>> I just dont understand where should I write the if defined (MACHINE32) etc

What do you mean ? That's already there in the header file :

#if defined(MACHINE32)

#elif defined(MACHINE64)

#else

#error 666

#endif /* MACHINE TYPE */

I should put that in the sizes.h file
>> I should put that in the sizes.h file

I think the best place for it is the extract.c file, because it's the only file where it's needed.

no the assignment told me to put it in sizes.h... can you please read the link I gave above for background reference
>> no the assignment told me to put it in sizes.h...

Then put it there ;) I was just saying where I'd put it.

I did read it vertically ...
>> I did read it vertically ...

I meant to say diagonally of course heh

and say that argv[1] is a --binary how do I compare that it is a --binary, how do you compare string in C?
>> how do you compare string in C?

Take a look at strcpy :

http://www.cplusplus.com/reference/clibrary/cstring/strcpy.html

well that just copies a string not compare it?
My mistake - I meant strcmp of course ;)

http://www.cplusplus.com/reference/clibrary/cstring/strcmp.html

so you read the assignment and you think that I should put it in the extract.h?
>> so you read the assignment and you think that I should put it in the extract.h?

When did I say that ? If the assignment says to put in in sizes.h, then put it there ...

well yeah, but here's a problem in main.c I should check if it int_u4 is 4 bytes or not and int_u8 is 8 bytes or not because when running the program I have to specify what machine I am using, say that I specify it's a 64 bit machine but it's actually a 32 bit machine then I should print

ERROR: size of (int_u4) is not 4, its' 8

this leads to a new question then, what is the type of int_u4 in 32 bit machine and what is it in 64 bit machine?? because I have to declare this under the if defined(MACHINE32)...
>> but here's a problem

I don't understand the problem. Just implement what you described :)

>> what is the type of int_u4 in 32 bit machine and what is it in 64 bit machine??

int_u8 is an unsigned integer type that is 8 bytes wide
int_8 is a signed integer type that is 8 bytes wide
int_u4 is an unsigned integer type that is 4 bytes wide
int_4 is a signed integer type that is 4 bytes wide

For each of the two systems, you have to pick the right integer types that fit these definitions. Take your pick out of short, int, long, long long. Just check which have the required size on which system, and use those.

okay, so I just do a sizeof the integer types in each system and pick whichever suits int_u8?? what if int_u4 turns out to have the same size in both system?? then the flaw wouldn't be detected.. say that int_u4 has the size 4 too in 64 bit machine and as well in 32bit machine
>> okay, so I just do a sizeof the integer types in each system and pick whichever suits int_u8??

Yes.

>> what if int_u4 turns out to have the same size in both system??

It WILL have the same size - that's how you defined it depending on the machine word size.

It will only go wrong if the wrong machine word size was specified (using either -DMACHINE32 or -DMACHINE64)

okay here's what I did:

typedef int int_4
typedef unsigned int int_u4
typedef long long int int_8
typedef unsigned long long int int_u8

so these typedefs are for both machine?? the MACHINE 32 and MACHINE 64?? I don't have to assign them differently ?
>> I don't have to assign them differently ?

Yes you do have to assign them differently, because the integer types might have different sizes on the different platforms. Check on both platforms which integer types fit your needs.

so therefore I have to find one that is different between the two machines right?? if they are both the same then i can't check the run time error for assigning the machine
The typedef's are compile time, and depend on which of -DMACHINE32 or -DMACHINE64 is specified.

If the right one is specified, then all runtime checks should succeed.
If the wrong one is specified, then some runtime checks might fail.

Right now, you're writing the differences between the 32bit and the 64bit system. You don't have to worry about errors right now. Just figure out which types need to be used on the two systems, and add the corresponding typedef's.

the thing is that I know know which type to use...
>> the thing is that I know know which type to use...

You have access to a 32bit and a 64bit machine (at least the assignment says so). You can easily find out using sizeof which integer types you need.

oh yes I just did that and I just did that a long int and an unsigned long int in a 32 bit machine is 4 bytes and in a 64 bit is an 8 byte so can this be used for the int_4 and int_u4 in the 32 bit machine??
>> so can this be used for the int_4 and int_u4 in the 32 bit machine??

Since they are 4 bytes on the 32 bit machine, sure. Now you just need to find a 4 byte integer type on the 64bit machine (try short).

nah I tried short and it's 2 byte.. what else can I try?? I am running out of options
>> nah I tried short and it's 2 byte

On the 64bit system ? And int is 8 bytes ? Then you don't have a 4 byte integer type :) Are you sure ?

no if it's just simply an int then it's 4 byte in the 64 bit system.. so we can use that as what?

both int in the 32 bit machine and the 64 bit machine are 4 byte
>> so we can use that as what?

What do you think ?

I think we can use that as int_4 in the 64 bit machine
>> I think we can use that as int_4 in the 64 bit machine

Sounds good :)

And the rest ?

now just the int_8 in the 32 bit machine.. I am guessing a long long int would work

yes a long long int works in 32 bit machine as 8 byte so we can use that as int_8 but a long long int is also 8 byte in 64 bit machine
Infinity08

membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Time for me to get some sleep - I'll be back in a few hours ;)

Continue the way you are - you're doing fine. Feel free to post the resulting code here for us to verify, as well as any questions you still might have.