Wie Sie manuell (bitweise) durchführen (float)x?

Nun, hier ist die header-Funktion von der Funktion bin ich soll zu implementieren:

/*
 * float_from_int - Return bit-level equivalent of expression (float) x
 *   Result is returned as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point values.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned float_from_int(int x) {
...
}

Wir dürfen nicht tun, float-Operationen oder jede Art von casting.

Nun habe ich versucht zu implementieren, der erste Algorithmus, da zu dieser Website: http://locklessinc.com/articles/i2f/

Hier ist mein code:

unsigned float_from_int(int x) {

//grab sign bit

  int xIsNegative = 0;
  int absValOfX = x;

  if(x < 0){
    xIsNegative = 1;
    absValOfX = -x;
  }




  //zero case
  if(x == 0){
    return 0;
  }
  if(x == 0x80000000){ //Updated to add this
    return 0xcf000000;
  }
  //int shiftsNeeded = 0;

  /*while(){

    shiftsNeeded++;
    }*/


  unsigned I2F_MAX_BITS = 15;
  unsigned I2F_MAX_INPUT = ((1 << I2F_MAX_BITS) - 1);
  unsigned I2F_SHIFT = (24 - I2F_MAX_BITS);

  unsigned result, i, exponent, fraction;

  if ((absValOfX & I2F_MAX_INPUT) == 0)
    result = 0;
  else {
    exponent = 126 + I2F_MAX_BITS;
    fraction = (absValOfX & I2F_MAX_INPUT) << I2F_SHIFT;

    i = 0;
    while(i < I2F_MAX_BITS) {
      if (fraction & 0x800000)
        break;
      else {
        fraction = fraction << 1;
        exponent = exponent - 1;
      }
      i++;
    }
    result = (xIsNegative << 31) | exponent << 23 | (fraction & 0x7fffff);
  }
  return result;
}

Aber es hat nicht funktioniert (siehe test Fehler unten):

ERROR: Test float_from_int(8388608[0x800000]) failed...
...Gives 0[0x0]. Should be 1258291200[0x4b000000]

Ich weiß nicht, wohin Sie gehen von hier aus. Wie gehe ich bei der Analyse der Schwimmer von diesem int?

EDIT #1:
Sie könnten in der Lage, um zu sehen, von meinem code, dass ich auch begann die Arbeit an diesem Algorithmus (besuchen Sie diese Website):

Bin ich davon ausgegangen, 10-bit, 2-Komplement, ganze zahlen, da die Mantisse ist nur
9 bits, aber der Prozess verallgemeinert, um mehr bits.

Save the sign bit of the input and take the absolute value of the input.
Shift the input left until the high order bit is set and count the number of shifts required. This forms the floating mantissa.
Form the floating exponent by subtracting the number of shifts from step 2 from the constant 137 or (0h89-(#of shifts)).
Assemble the float from the sign, mantissa, and exponent.

Aber das scheint nicht richtig. Wie könnte ich konvertieren, 0x80000000? Nicht sinnvoll ist.

EDIT #2:
Ich denke, es ist, weil ich sage, max bits 15... hmmm...

EDIT #3: Schraube, die den alten Algorithmus, ich bin starting over:

unsigned float_from_int(int x) {

  //grab sign bit

  int xIsNegative = 0;
  int absValOfX = x;

  if(x < 0){
    xIsNegative = 1;
    absValOfX = -x;
  }


  //zero case
  if(x == 0){
    return 0;
  }
  if (x == 0x80000000){
    return 0xcf000000;
  }

  int shiftsNeeded = 0;

  int counter = 0;
  while(((absValOfX >> counter) & 1) != 1 && shiftsNeeded < 32){

    counter++;
    shiftsNeeded++;
  }

  unsigned exponent = shiftsNeeded + 127;

  unsigned result = (xIsNegative << 31) | (exponent << 23);

  return result;

Hier ist die Fehlermeldung die ich bekomme auf diesen einen (ich glaub ich hab den letzten Fehler):

ERROR: Test float_from_int(-2139095040[0x80800000]) failed...
...Gives -889192448[0xcb000000]. Should be -822149120[0xceff0000]

Kann hilfreich sein, zu wissen, dass:
absValOfX = 7f800000
(mit printf)

EDIT #4: Ah, ich bin der Suche nach der exponent falsch, müssen für die Zählung von Links, dann subtrahieren von 32 glaube ich.

EDIT #5: ich habe angefangen, jetzt versucht, befassen sich mit komisch Rundung Probleme...

  if (x == 0){
    return 0; //0 is a special case because it has no 1 bits
  }
  if (x >= 0x80000000 && x <= 0x80000040){
    return 0xcf000000;
  }
  //Save the sign bit of the input and take the absolute value of the input.
  unsigned signBit = 0;
  unsigned absX = (unsigned)x;
  if (x < 0)
    {
      signBit = 0x80000000u;
      absX = (unsigned)-x;
    }

  //Shift the input left until the high order bit is set to form the mantissa.
  //Form the floating exponent by subtracting the number of shifts from 158.
  unsigned exponent = 158;
  while ((absX & 0x80000000) == 0)
    {
      exponent--;
      absX <<= 1;
    }

  unsigned negativeRoundUp = (absX >> 7) & 1 & (absX >> 8);

  //compute mantissa
  unsigned mantissa = (absX >> 8) + ((negativeRoundUp) || (!signBit & (absX >> 7) & (exponent < 156)));
  printf("absX = %x, absX >> 8 = %x, exponent = %i,  mantissa = %x\n", absX, (absX >> 8), exponent, mantissa);
  //Assemble the float from the sign, mantissa, and exponent.
  return signBit | ((exponent << 23) + (signBit & negativeRoundUp)) | ( (mantissa) & 0x7fffff);

-

absX = fe000084, absX >> 8 = fe0000, exponent = 156,  mantissa = fe0000
ERROR: Test float_from_int(1065353249[0x3f800021]) failed...
...Gives 1316880384[0x4e7e0000]. Should be 1316880385[0x4e7e0001]

EDIT #6

Ging es wieder, noch ist die Rundung nicht richtig funktioniert. Ich habe versucht, zu hacken zusammen einige Runden, aber es will einfach nicht funktionieren...

unsigned float_from_int(int x) {






  /*
  If N is negative, negate it in two's complement. Set the high bit (2^31) of the result.
    If N < 2^23, left shift it (multiply by 2) until it is greater or equal to.
    If N ≥ 2^24, right shift it (unsigned divide by 2) until it is less.
    Bitwise AND with ~2^23 (one's complement).
    If it was less, subtract the number of left shifts from 150 (127+23).
  If it was more, add the number of right shifts to 150.
    This new number is the exponent. Left shift it by 23 and add it to the number from step 3.
  */

  printf("---------------\n");
  //printf("x = %i (%x), -x = %i, (%x)\n", x, x, -x, -x);
  if(x == 0){
    return 0;
  }

  if(x == 0x80000000){
    return 0xcf000000;
  }

  //If N is negative, negate it in two's complement. Set the high bit of the result
  unsigned signBit = 0;

  if (x < 0){
    signBit = 0x80000000;
    x = -x;
  }

  printf("abs val of x = %i (%x)\n", x, x);

  int roundTowardsZero = 0;
  int lastDigitLeaving = 0;
  int shiftAmount = 0;
  int originalAbsX = x;

  //If N < 2^23, left shift it (multiply it by 2) until it is great or equal to.
  if(x < (8388608)){
    while(x < (8388608)){
      //printf(" minus shift and x = %i", x );
      x = x << 1;
      shiftAmount--;
    }
  } //If N >= 2^24, right shfit it (unsigned divide by 2) until it is less.
 else if(x >= (16777215)){
    while(x >= (16777215)){

      /*if(x & 1){
        roundTowardsZero = 1;
        printf("zzz Got here ---");
        }*/

      lastDigitLeaving = (x >> 1) & 1;
      //printf(" plus shift and x = %i", x);
      x = x >> 1;
      shiftAmount++;

    }
    //Round towards zero
    x = (x + (lastDigitLeaving && (!(originalAbsX > 16777216) || signBit)));




    printf("x = %i\n", x);
    //shiftAmount = shiftAmount + roundTowardsZero;
  }

  printf("roundTowardsZero = %i, shiftAmount = %i (%x)\n", roundTowardsZero, shiftAmount, shiftAmount);

  //Bitwise AND with 0x7fffff
 x = x & 0x7fffff;

  unsigned exponent = 150 + shiftAmount;

  unsigned rightPlaceExponent = exponent << 23;

  printf("exponent = %i, rightPlaceExponent = %x\n", exponent, rightPlaceExponent);

  unsigned result = signBit | rightPlaceExponent | x;

  return result;
  • Sollte absValOfX ohne Vorzeichen sein?
  • Ich bin mir nicht sicher, aber ich glaube nicht, dass wir erlaubt sind, zum umwandeln eines int an einen unsigned. Auch wäre es egal, richtig? Denn eine positive int verhält sich wie eine Menge, unsigned? (Ich weiß nicht)
  • Ich bin mir nicht sicher, was zu sagen, aber manchmal, wenn Sie tun etwas und verschiebt Dinge auf Ganzzahlen mit Vorzeichen seltsame Dinge passieren können. Ein weiteres Problem ist, dass Ihr Ergebnis Wert niemals negativ sein, weil es nicht signiert.
  • 0x80000000 ist ein spezieller Fall von Ganzzahlen mit Vorzeichen. Es ist das einzige, das seine eigene zwei-Komplement. Es ist die negative Zahl und nicht noch eine passende positive Zahl.
  • Aber, wenn Sie die Umwandlung 0x80000000 auf eine unsigned, es kommt als 0x80000000. Daher ist, wie einen schönen Konter-speziellen-Fall zu tun int x; if(x<0) x = -x; unsigned v = (unsigned)x; erzeugt immer den richtigen absoluten Wert in v.
  • Übrigens, würde ich prüfen, signed-unsigned-Wandlung, um ein legales "signed/unsigned" - operation, aber natürlich habe ich angenommen, die Letzte Entscheidung liegt, wer hat das problem. Wenn Sie nicht tun können, die Konvertierung dann müssen Sie sich für special-Gehäuse 0x80000000.
  • Siehe dieser Beitrag: stackoverflow.com/questions/12342926/...
  • Duplikate: Umwandlung von float zu int (bitweise) in C, Konvertierung von Int zu Float oder Float zu Int Bitweise Operationen (software floating point), Wie wandelt einen unsigned int in einen float?

InformationsquelleAutor | 2012-09-09
Schreibe einen Kommentar