[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Normazile float numbers

Posted on 2005-04-13
23
Medium Priority
?
601 Views
Last Modified: 2010-04-15
How can I Normalize two float numbers


Suppose the input of users as this

1.98 x 10E 4   = 19800
 21.22 x 10E5 = 2120000

But I need to set them as

0.19 x 10 E -5
and the second one must be 0 in the first digit and must be the same exponent
0.2122 x 10E-6 -> as this is greater than first I must move the coma of the first one

0.019 x 10 E -6
0.2122 x 10 E -6

I need to make this in a single function.


0
Comment
Question by:djhex
  • 11
  • 7
  • 4
22 Comments
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 13780310
Hi djhex,

Is the user entering 1.98 x 10E4  or  19800?

If the first, you've made a whole lot of work for yourself.  If the second, the math conversion routines should normalize the value for you.

If scientific notation is required, have the user enter 1.98E4.  The math library will convert it.

Oh -- use scanf(), or better yet, sscanf() to convert the input to floating point.


Good Luck!
Kent
0
 
LVL 10

Author Comment

by:djhex
ID: 13781570
The user can enter the value as he wishes and I need to normalize it and show the output. as I showed on the example

Does scanf normalizes it automatically? Because I an giving these parameters to an assembly program
0
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 13781813

Some combination of %f and %e should work for conversions.  It's been quite a while since I've used exponential notation, but there aren't a lot of "moving parts"

"%e" is the format specifier for Exponential Notation.  "%f" might also work on the read, I don't recall.

float FloatValue;
  scanf ("%e", &FloatValue);

The normal behavior is that floating point values are normalized.



Kent

0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 5

Expert Comment

by:libin_v
ID: 13785135
Firstly,
1.98 x 10E4 = 19800 = 0.19*10e5 (not 0.19 x 10 E -5 . This messed up my program, was getting wierd answers)
21.22 x 10E5 = 2120000 = 0.2122*10e6 (not 0.2122 x 10E-6)

Secondly,
      Normalization means to put the decimal point to the left-most non-zero digit.
      It is not depended on the second number.

      The shifting as u said takes place in binary operation as add and subract, only.
u will find it logical by reading the algorithms below.
(From Computer Organization-> By Carl Hamacher,
 Zvonko Vranesic, Safwat Zaky. Mc-Graw Hill Pub.)

Add/Subtract Rule
-----------------
     3.25 x 10 ** 3
   + 2.63 x 10 ** -1
     ---------------
1.      Choose the number with the smallest exponent and shift its mantissa right a number of steps equal to the difference in exponents.
     3.25         x 10 ** 3
   + 0.000263 x 10 ** 3
     -----------------------
2.      Set the exponent of the result equal to the larger exponent
     3.25         x 10 ** 3
   + 0.000263 x 10 ** 3
     ------------------------
                    x 10 ** 3
3.      Perform Addition and subraction of mantissa
     3.25         x 10 ** 3
   + 0.000263 x 10 ** 3
     --------------------
      3.250263 x 10 ** 3
4.      Normalize the resulting value (if neccessary).

      In the below to algorithms shifting of mantissa is not done, as u will notice.
Multiply Rule
-------------
1.      Add the exponents
2.      Multiply the mantissa
3.      Normalize the resulting value (if neccessary).

Divide Rule
-----------
1.      Subtract the exponents
2.      Divide the mantissa
3.      Normalize the resulting value (if neccessary).

******************************************
      The above said shifting is done by the processor automatically.
But I suppose U want to do it manually, using a C code.

      In C the normailzed form is different, ie the decimal point is immediatly after the left-most non-zero digit.
Thus, calls for another structure normalized float.
******************************************

#include <stdio.h>
#include <math.h>

typedef struct {
      long mantissa;            /* all digits from the left-most non-zero digit to the right-most non-zero digit */
      int pow;
} norm_float;

norm_float normalize (float f);      /* to normalize the float */
norm_float add (norm_float nf1, norm_float nf2);      
/* an illustration of shifting the mantissa using add operation */
float to_float (norm_float nf);
/* convert your normailzed_float to c_float */
void print_nf (norm_float nf);      /* prints your norm_float*/

void main()
{
      norm_float nf1, nf2, nfr;

      nf1 = normalize (1.98e4);
      printf ("nf1 = ");
      print_nf (nf1);
      printf ("\n");

      nf2 = normalize (21.22e5);
      printf ("nf2 = ");
      print_nf (nf2);
      printf ("\n");

      nfr = add (nf1, nf2);
      printf ("Sum = ");
      print_nf (nfr);
      printf ("\n");
}

norm_float normalize (float f)
{
      long t;
      float tmp;

      norm_float n_f;
      n_f.pow = 0;

      tmp = f;

      /* removing the decimal point eg:1.987 to 1987 */
      while (tmp != floor(tmp)) {
            n_f.pow ++;
            tmp *= 10;
      }

      /* extracting the mantissa */
      n_f.mantissa = (long)tmp;

      /* removing the 0's in the right eg:19800 to 198 */
      while (n_f.mantissa != 0 && n_f.mantissa%10 == 0)      
        {
            n_f.mantissa /= 10;
            n_f.pow++;
      }

      /* getting the power eg:making 198 to .198 */
      t = n_f.mantissa;
      while (t != 0) {
            t /= 10;
            n_f.pow++;
      }

      return n_f;
}

norm_float add (norm_float nf1, norm_float nf2)
{
      norm_float result;
      norm_float tmp;
      long tr;
      int nod_1 = 0,nod_2 = 0; /*nod => no of digit */

      /* counting no. of digits in mantissa */
      tmp = nf1;
      while (tmp.mantissa != 0) {
            tmp.mantissa /= 10;
            nod_1++;
      }

      /* counting no. of digits in mantissa */
      tmp = nf2;
      while (tmp.mantissa != 0) {
            tmp.mantissa /= 10;
            nod_2++;
      }

      /* the reason behind counting the digits is
      because, in the above addition algorithm, the
      shifting was to the right of mantissa of
      smallest exponent, that is padding the left
      with zeroes.
      Since this is not possible, we will pad the
      right of the mantissa of largest exponent, ie
      shifting to the left.
      But the no. of shifts is not the same.
      Eg: (When done according to above algo)
           0.3256 x 10 ** 3                  0.3256    x 10 ** 3
         + 0.263  x 10 ** -1 ==>      0.0000263 x 10 ** 3
            no of shifts = 4
          (but when using my method)
           3256            3256000
         + 263  ==>                 263
            no of shifts = 3 (forget the power for now)
      Thus, if u notice the
      no of shift = diff.in power - diff.in no of digits
      */
      /* Checking which power is greatest */
      if (abs(nf1.pow) > abs(nf2.pow)) {
            result.pow = nf1.pow;
            nf1.mantissa *= pow(10, abs( f1.pow-nf2.pow)
                                        - (nod_1-nod_2));
            tmp = nf1;
      }
      else {
            result.pow = nf2.pow;
            nf2.mantissa *= pow(10, abs( f1.pow-nf2.pow)                
                                        -(nod_2-nod_1));
            tmp = nf2;
      }
      /* performing addition */
      result.mantissa = nf1.mantissa + nf2.mantissa;

      /* normalizing result */
      tr = result.mantissa;
      while (tr != 0 && tmp.mantissa != 0) {
            tr /= 10;
            tmp.mantissa /= 10;
      }

      if (tr != 0 && tmp.mantissa == 0)
            result.pow++;
      else if (tr == 0 && tmp.mantissa != 0)
            result.pow--;

      /* remove 0's in the right eg: 599 + 11 = 600 to 6
      while (result.mantissa != 0 &&
                  result.mantissa%10 == 0)
            result.mantissa /= 10;

      return result;
}

float to_float (norm_float nf)
{
      return nf.mantissa*pow(10,nf.pow);
}

void print_nf (norm_float nf)
{
      printf ("%ld*10^%d", nf.mantissa, nf.pow);
}
0
 
LVL 10

Author Comment

by:djhex
ID: 13785242
Thank you very much to all of you. One last question that is not clear to me.


 After normalization the binary IEEE representation of the (7 or 8 bit of the exponents will be the same?)

I ask this. because I am supposed to do an addition in assembler but calling the function from C. I already made the link between assembly and C.
0
 
LVL 5

Expert Comment

by:libin_v
ID: 13785271
Explain briefly, i didnt get u
0
 
LVL 10

Author Comment

by:djhex
ID: 13785285
http://babbage.cs.qc.edu/courses/cs341/IEEE-754.html

I tried this with the numbers

  3.25         x 10 ** 3
   + 0.000263 x 10 ** 3

These numbers suppose to have the same exponent but the exponent bits are not the same. :(

0
 
LVL 5

Expert Comment

by:libin_v
ID: 13785358
the no. are in the form
mantissa*2^exp in binary (or internal representation)

and not
mantissa*10^exp

thus not the same
0
 
LVL 10

Author Comment

by:djhex
ID: 13785388
SO I got a problem.
0
 
LVL 5

Expert Comment

by:libin_v
ID: 13785391
try this

put 1020 in the site u me
and put 520

u get the same exp
0
 
LVL 10

Author Comment

by:djhex
ID: 13785418
thats what I want to DO. My assembler function must receive the 2 float numbers and its internal repreesntation of the exponent must be equal. So in that way I can make a normal addition in assembly without having to worry about it. But as I can see I will have to do it everything from assembly
0
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 13785443

Oh, the problems are worse than you think.  :(

All of the discussion so far assumes positive values.  The rules change a bit when you consider negative numbers!


Kent
0
 
LVL 5

Expert Comment

by:libin_v
ID: 13785448
u mean to say, u need help in assembly coding or pass the two float numbers to the assembly program with their exponents being equal
0
 
LVL 5

Expert Comment

by:libin_v
ID: 13785463
kdo,
my code works fine if the nubers are -ve
0
 
LVL 10

Author Comment

by:djhex
ID: 13785480
SO I want to cry.


0
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 13785508
Hi libin_v,

It appears that the code works fine for negative exponent.   6.12E-4, etc.

What about negative value?   -6.12E+2, etc.


Kent
0
 
LVL 5

Expert Comment

by:libin_v
ID: 13785522
Just works as expected
0
 
LVL 5

Expert Comment

by:libin_v
ID: 13785606
djhex,
u mean to say, u need help in assembly coding or pass the two float numbers to the assembly program with their exponents being equal
0
 
LVL 5

Accepted Solution

by:
libin_v earned 1000 total points
ID: 13786305
This program makes both the floats to a common exponent

#include <stdio.h>

long get_mantissa (long t);
long get_power (long t);
char get_sign (long t);
void make_comm_exp (long *l1, long *l2);
void change (long *l, long pow);

void main()
{
      float f1 = 1020;
      float f2 = 510;
      long *l1 = &f1, *l2 = &f2;
      long pow1, pow2;
      long fr1, fr2;
      char sign1, sign2;

      sign1 = get_sign (*l1);
      sign2 = get_sign (*l2);
      pow1 = get_power(*l1);
      pow2 = get_power(*l2);
      fr1 = get_mantissa (*l1);
      fr2 = get_mantissa (*l2);

      printf ("Before conversion\n");
      printf ("float1 %5.0f in binary = %lX\n", f1, *l1);
      printf ("Sign = %X\tExp = %lX\tMantissa = %lX\n",sign1, pow1, fr1);
      printf ("\n");
      printf ("float2 %5.0f in binary = %lX\n", f2, *l2);
      printf ("Sign = %X\tExp = %lX\tMantissa = %lX\n",sign2, pow2, fr2);

      make_comm_exp (l1, l2);

      sign1 = get_sign (*l1);
      sign2 = get_sign (*l2);
      pow1 = get_power(*l1);
      pow2 = get_power(*l2);
      fr1 = get_mantissa (*l1);
      fr2 = get_mantissa (*l2);

      printf ("\n\n\nAfter conversion\n");
      printf ("float1 %5.0f in binary = %lX\n", f1, *l1);
      printf ("Sign = %X\tExp = %lX\tMantissa = %lX\n",sign1, pow1, fr1);
      printf ("\n");
      printf ("float2 %5.0f in binary = %lX\n", f2, *l2);
      printf ("Sign = %X\tExp = %lX\tMantissa = %lX\n",sign2, pow2, fr2);

}

void make_comm_exp (long *l1, long *l2)
{
      long pow1, pow2;
      pow1 = get_power(*l1);
      pow2 = get_power(*l2);
      if (pow1 > pow2)
            change (l2, pow1);
      else if (pow2 > pow1)
            change (l1, pow2);
      else
            printf ("Do not need change\n");
}

void change (long *l, long pow)
{
      long fr, pow1;
      char sign;

      pow1 = get_power (*l);
      fr = get_mantissa (*l);
      sign = get_sign (*l);

      fr = fr >> (pow - pow1);
      if (sign == 1)
            fr = fr | 0x00400000;

      pow1 += (pow - pow1);
      pow1 = pow1+127;
      pow1 = pow1 << 23;

      *l = 0;
      *l = fr | pow1;
      if (sign == 1)
            *l = *l | 0x80000000;

      pow1 = get_power (*l);
      fr = get_mantissa (*l);
      sign = get_sign (*l);
}

long get_mantissa (long t)
{
      long fr;
      fr = t & 0x007fffff;
      return fr;
}

long get_power (long t)
{
      long pow;
      pow = t >> 23;
      pow = pow & 0x000000ff;
      pow = pow - 127;
      return pow;
}

char get_sign (long t)
{
      char sign;

      sign = t>>31;
      return sign;
}
0
 
LVL 5

Expert Comment

by:libin_v
ID: 13786309
works for boths +ve and -ve floats
0
 
LVL 5

Expert Comment

by:libin_v
ID: 13786343
in my compiler float and long is 32bits
0
 
LVL 10

Author Comment

by:djhex
ID: 13786366
I didnt understand almost anything but You get the points. Please watch the assembly thread maybe you can help me.

If you or your friends have made an assembly addition without using FPU I really need it.


YOu got a feed back
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and inf…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.
Suggested Courses
Course of the Month18 days, 12 hours left to enroll

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question