0

I am taking Computer Architecture subject at University, and I was assigned to program a tool which would take floating point number as input, I guess store it in memory and printout hexadecimal form of the binary representation of the number in IEEE 784 standart.

Now I am certain about the algorithm of converting any decimal floating point number to its binary form in IEEE 784 on paper yet I struggle to come up with a solution for assembler (numbers can be such as -157.4, 0.5, -0.6 and etc.).

My guesses are that I would need to extract the sign, the exponent and mantissa from input using ASCII codes and string manipulation and store either 0 or 1 in memory for the sign, convert what's before the . sign to binary form and shift bits right or left till I get one number, storing the amount of times the program had to shift right (that and +127 would be exponent, right?). Then somehow I should deal with the remaining part of the entered numbers (after . ). Should I multiply it by two, like on paper, or is there a method for this sort of problem? Lastly, the program should convert each 4bits to hex, but I am not sure how.

I don't want copy - paste solutions, I am seeking to learn assembler, to understand inner processes, not just finish the assignments. If anyone has ever dealt with such problems, where should I go first. What should I study? I have nearly three weeks for the task.

(last bit - both emu8086 and NASM should be able to assemble the program).

Thank you!

Lukas Valatka
  • 103
  • 1
  • 14
  • Thanks, still, I want to understand how should I deal with mantissas part after . (which would definately be floating point number). Should I use the algorithm of multiplying by two like on paper? What if I do not have access to FPU? How then should should I solve the problem? – Lukas Valatka Sep 29 '15 at 06:12
  • What exactly are you hoping for? It sounds like you're asking for someone to write you a complete program in x86 asm that solves the entire problem. That's obviously a close->too broad question. It sounds like you don't want to call `scanf` or `atof` do the string->IEEE 754 (not 784, BTW). Do you want to write code that goes directly from a string to the sign / exponent / mantissa bits "manually", rather than by multiplying and adding FP values as you process digits of the string? Doing it in asm has no particular advantage, if you aren't using machine int->FP instructions. – Peter Cordes Sep 29 '15 at 07:16
  • You could possibly also make use of some of the more obscure x87 FPU instructions for manipulating FP values. Learning x87 FPU is not particularly useful at this point, other than for disassembling old software, since any new x86 asm FP code should use SSE/SSE2. IDK how helpful any x87 FPU instructions might be, since I don't remember what's available. I think there's something for efficiently multiplying by powers of 2. (i.e. adding to the exponent field.) If you write this in C, you should make it a bitfield. `struct { int s:1, e:8, m:23; };`, maybe as a union with a `float`. – Peter Cordes Sep 29 '15 at 07:21
  • 1
    To convert the fractional part from decimal to binary without FPU is very difficult. For converting with FPU take a look [here](http://stackoverflow.com/a/23547744/3512216). – rkhb Sep 29 '15 at 07:47
  • @rkhb: Wouldn't it work to do something like: **1.** remove the decimal point and convert the string of digits to an integer. **2.** Store the high 23 bits of that in the mantissa. **3.** Set the exponent based on where the decimal point was. base2 vs. base10 -> log10 vs. log2 is a complicating factor in working out the exponent, I'm sure, but it doesn't sound too bad. – Peter Cordes Sep 29 '15 at 08:23
  • @PeterCordes: Let's make an example based on your suggestion (as I understand it): Input: 1.75, without point: 175, integer: 10101111 ... How would you come to the correct binary: 1.11? – rkhb Sep 29 '15 at 08:37
  • I voted for reopening the question, because it's about converting a decimal floating point number to IEEE-754 and not vice versa as in the "duplicate". – rkhb Sep 29 '15 at 08:47
  • yeah, it's not an exact duplicate. I voted to close as "too broad", not duplicate, since I agree that other question is different. The decimal string -> IEEE-754 binary is not a bad question, but the question as written is also asking about asm, so it's at least two questions in one. re: my conversion algo: I think the problem was leaving the base10->base2 conversion until after taking out the decimal point. The mantissa is also between 1.0 and 2.0, as http://www.h-schmidt.net/FloatConverter/IEEE754.html explains, and has an implicit leading 1.0. Thanks for sanity-checking that idea. :P – Peter Cordes Sep 29 '15 at 08:52
  • @LukasValatka: http://www.h-schmidt.net/FloatConverter/IEEE754.html suggests reading the libc source code for string->float conversion (e.g. `strtof`), since that's what it uses. – Peter Cordes Sep 29 '15 at 08:53
  • @rkhb: I found an english writeup explaining how glibc's `strtod` operates, which should answer that part of the OP's question: http://www.exploringbinary.com/how-glibc-strtod-works/ – Peter Cordes Sep 29 '15 at 09:08

1 Answers1

0

You're asking two questions in one.

  1. How to convert a string to an IEEE-754 float? Ok, interesting question, and more complicated than you might expect. Getting even the very last bit rounded correctly requires a lot of work.

  2. How do I do this in x86 asm? Silly question; the same way you code any algorithm in asm. The simplest answer to this is to write it in C, and look at the compiler output. The obsolete x87 FPU has some instructions that do sort of bitwise things with FP values, but normal FPUs like SSE don't have that. SSE just has conversion to/from integers, and normal math ops. (And of course you can use vector-integer ops on the same registers). Anyway, "how do I write this in asm" is not an interesting question if you don't already have a correct algorithm and an attempt at implementing it.


An online IEEE-754 calculator recommends looking at the libc source code for converting strings to floats and vice versa.

I found a nice writeup and analysis of GNU libc's strtof/strtod functions, which also compares it to David Gray's implementation which is used in Python, PHP, Java, and several web browsers, among other things.

quick summary:

  1. Parse the decimal string into integer and fractional parts.

  2. Convert those parts to binary separately, to extended-precision integers (using gmp routines).

  3. If the integer part has enough significant bits to fill the mantissa, you don't have to look at the fractional part. Otherwise, get bits from the fractional part.

The fractional part is tricky: it can have leading zeros, so it's represented as a fraction. e.g. .00123 = 123/105. Getting the required number of bits for the mantissa out of this fraction is done with extended-precision integer division, typically only using a couple div instructions rather than computing and throwing away most of the full extended-precision division result.


Once you have a 32bit float value, you can print it as a hex string the same way as you would for any 32bit integer. Base16 is super convenient, because every 8 bits maps to two hex digits. Printing integers in base10 typically requires repeated division by 10 until the number is <= 9, but in base16 that's just a bit-shift by 4.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • You may be making it a bit harder than required. The primary task is taking the input and then storing it in memory as floating point. The conversion into IEEE-754 is handled by the kernel. To take input and then intentionally store it in IEEE-754 is like saying take integer input and store it in two-compliment format. It's what the box does. The real question is (1) how do I find the IEEE-754 representation. Once stored as floating point, the 32-bits at that address are in, and can be read directly, to get the IEEE-754 representation. – David C. Rankin Sep 30 '15 at 03:36
  • @DavidC.Rankin: Sorry, you're completely wrong. Reading user input gives you a string. Neither the kernel nor any one CPU instruction will convert it to a 32bit float for you. That's why the `strtof(3)` library function exists. Printing that 32bit value is trivial. In C, just use a union to type-pun it to a 32bit integer. In asm, just `movd` to transfer the low 32bits from an xmm (SSE) register to an integer register, or `movss` to store it to 32b of memory. The Linux kernel doesn't internally use FPl: http://stackoverflow.com/questions/13886338/use-of-floating-point-in-the-linux-kernel – Peter Cordes Sep 30 '15 at 03:49
  • Maybe you're thinking of `scanf("%f", &my_float)`. That's a library function, not a system call. It internally uses `strtof` for float conversions. – Peter Cordes Sep 30 '15 at 03:52