Search code examples
floating-pointmipsdivision

How to check the Rest in a Floating point division in MIPS?


i'm trying to make a division for 2 in MIPS, (i'm using PCSPIM). basically i have a number in a register ($f0), loaded. after some operations, i would like to divide this number for 2, and check if there is a rest from this operation (for example from 50 i don't expect a rest, but from 23 yes). i don't know how to make the division and check for the rest. at the moment the code is working only if the number is like a number between 2 and 3. if the input is 5 for example, it won't work properly.

".

i leave the code (sorry for some italian comments, i hope that can be understandable).

    .data
memoria: .space 1000
numero: .float 5.00
numero1: .float 1.00
numero2: .float 2.00
    .text

main:
    l.s $f0, numero
    l.s $f1, numero1
    la $s0, memoria

CICLO:
    addiu $sp, $sp, -4
    swc1 $f0, 0 ($sp)
    jal CHECKNUMEROPARI             #NUMBER IS EVEN?
    lwc1 $f0, 0($sp)
    addiu $sp, $sp, 4
CHECKNUMEROPARI:        #I HAVE TO CHECK THE DIVISION. IF NO REST, IS EVEN.
    #########HERE THERE IS THE PROBLEM###############

        l.s $f2, numero2
    div.s $f0, $f0, $f2
    c.eq.s $f0, $f1
    bc1t PARI       #SO IS EVEN
    #ALLORA è DISPARI   
    l.s $f3, numero1    #LIKE SO IN F3 I WILL HAVE A NUMBER THAT WILL LET ME KNOW THAT I HAVE A ODD NUMBER
    jr $ra


PARI:
    l.s $f3, numero2    #IN F3 I WILL HAVE A NUMBER THAT WILL LET ME KNOW THAT I HAVE A EVEN NUMBER
    jr $ra
    

i tried converting the number to integer, but it doesn't work (and otherwise i dont like the concept of converting it).


Solution

  • Most technically, you can examine the exponent field and also the mantissa.  The exponent field informs how many bits are integral, and thus, how many are the rest, which if non-zero are the fractional part.  This is not simple to do, though.  it needs and'ing, shifting, which can be done only in the integer registers, but that doesn't mean converting to integer, just move the float value from float register to integer register directly without conversion to perform the above.

    With floating point, the exponent indicates a power of 2 and so dividing by 2 means subtracting 1 from the exponent, and thus, won't change the mantissa.

    For more detail, for IEE754 32 bit single float, an exponent encoded as 127 means 20 while 128 means 21, and so on.  That power number tells us how many digits belong as integer, i.e. where the boundary is between integer part and fractional part in the mantissa.  If any fractional digits are non zero then it is not an integer.

    +-+-------+-+----------------------+
    |1|   8   |1|       23             |
    +-+-------+-+----------------------+
     S   exp   h      mantissa
    
    • S is the overall sign bit, and from here on we'll ignore it for simplicity.

    • exp is the exponent value, which is biased by 127 to allow for both positive and negative exponents without a second sign bit.

    • h is a hidden 1 bit that is not represented, since, when normalized, all floating point values (except 0) start with a leading 1 (and so by not representing that we get an get extra bit of precision).

    The floating point number is represented by the formula 2exp-127 × (1 + 0.mantissa)

    The exp effectively tells us which bits are integer bits in the mantissa.

    We can extract the exponent portion with the formula:

    exp = (floatBits >> 23) & 255
    

    If the exponent value is 126 or less, then the entire number is fractional because it is < 1.0 .

    If the exponent is 127, then all mantissa bits must be zero (the value is 1.0) or else there is some fractional portion (i.e. the number is between 1.0 and 2.0, e.g. 1.x, so not integral).

    When higher than 127 you'll have to check the proper bits for zero/nonzero and ignore the number of integer bits in the mantissa.  For example, with 128 you have 1 bit that can be 1 or 0 while the rest represent fractional bits, so if they are non-zero then the value is non-integeral.


    Converting to integer alone is insufficient to tell us anything.

    So alternatively, convert to integer, then back to float and compare the original float with the new one.  If they're the same it was an integer to start with and if not, it lost a fraction, so wasn't an integer.

    You can also convert to double, then int 64 then back to double with same comparison as above but less room for overflow.