在C 4byte浮动ieee754中没有运算符的乘法和除法

时间:2013-12-06 13:19:38

标签: c math floating-point bit-manipulation ieee-754

我需要一些帮助来编程。 我必须编写一个程序,它可以在没有操作符的情况下进行分频和乘法,并且包含IEEE 754标准。我只能使用+, - ,否定和逻辑运算。需要从文件中读取数字和运算符。

到目前为止,我得到了这个,但它无法正常工作。

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>

float mult(float a, float b) {
    float i = 0;
    float c = 0;
    while (i < b) {
        c = c + a;
        i++;
    }
    return c;
}


//this will be needed to divide
float product=1,multiplier=2,a=1;
int steps=0;
void divCore(float number, float divideBy,float lastDivison)
{
    steps++;
    if(number - divideBy < 
        return;
    else
    {
        lastDivison = divideBy;
        divideBy *= multiplier;
        if(number >= divideBy)
        {
            product *= multiplier;
            divCore(number,divideBy,lastDivison);
        }
        else
        {
            a *= 0.5;
            multiplier = 1 + a;
            divCore(number,lastDivison,lastDivison);
        }
    }
}
//its an other function for division ,you use this in main
float Divide(float numerator, float denominator)
{
    //init data
    int neg=(numerator<0)?-1:1;
    neg*=(denominator<0)?-1:1;
    product = 1;
    multiplier = 2;
    a = 1;
    steps =0;
    divCore(abs(numerator),abs(denominator),0);
    return product*neg;
}

int main()
{
    float i,j;
    char c[2];
    FILE *in=fopen("input.txt","r");
    fscanf(in,"%f",&i);
    fscanf(in,"%s",c);
    fscanf(in,"%f",&j);
    if(strcmp(c,"*")==0){
        float a = mult(i,j);
        printf("%f\n", a);
    }
    if(strcmp(c,"/")==0){
        float a2 = Divide(i,j);
        printf("%f\n", a2);
    }

    getchar();
    getchar();
}

文件看起来像这样(我认为数字不算):

0x0000C942
*
0x0000C942

1 个答案:

答案 0 :(得分:2)

只是为了好玩(所以不要请求downvote)。此代码遵守任务中提供的规则;-) ie。不使用C除法(/)或乘法(*)运算符:

float mult(float a, float b)
{
    float m;

    _asm
    {
        fld a
        fld b
        fmul
        fstp m
    }

    return m;
}

float div(float numerator, float denominator)
{
    float d;

    _asm
    {
        fld numerator
        fld denominator
        fdiv
        fstp d
    }

    return d;
}

由于此处没有人提供解决方案是乘法(仅标准化):

float mul(float a, float b)
{
    // for normalized floats only

    unsigned int a_bits = *((unsigned int*)&a);
    unsigned int b_bits = *((unsigned int*)&b);

    // hints (* means 'any value')
    // ------------------------------------
    // sign | exp_bits | coeff_bits | value
    // ------------------------------------
    //   0  |    0     |     0      | +0.0
    //   1  |    0     |     0      | -0.0
    // ------------------------------------
    //   *  |    0     |    !0      | we'll not handle denormalized here
    //   *  |0x01-0xFE |     *      | (-1)^s * 1.coeff * 2^(exp_val-127)
    // ------------------------------------
    //   0  |   0xFF   |     0      | +Inf  0x7F800000
    //   1  |   0xFF   |     0      | -Inf  0xFF800000
    // ------------------------------------
    //   *  |   0xFF   |    !0      | NaN  for example 0x7FFFFFFF (8388607 NaN representations)
    // ------------------------------------

    // if bits 0..30 are 0 (ie. both exp and coeff bits are all 0)
    // then our number is zero and multiplication result is zero
    if ( ((a_bits << 1) == 0) || ((b_bits << 1) == 0)) // << 1 clears sign bit
    {
        return 0.0;
    }

    int a_exp_bits = (a_bits >> 23) & 0xFF;
    int b_exp_bits = (b_bits >> 23) & 0xFF;

    // when exp bits are 0xFF = value may be +-Inf or Nan so result is NaN too
    if ( (a_exp_bits == 0xF) || (b_exp_bits == 0xF))
    {
        unsigned int NaN = ~(1 << 31); // this is one of 8388607 NaN representations
        return *((float*)&NaN);
    }

    int a_exp_val = a_exp_bits - 127;
    int b_exp_val = b_exp_bits - 127;

    int a_coeff_bits = a_bits & ((1 << 24) - 1);
    int b_coeff_bits = b_bits & ((1 << 24) - 1);

    // let's multiply
    unsigned long long a24 = (unsigned long long)a_coeff_bits | (1LL << 23); // add implicit 24th bit
    unsigned long long b24 = (unsigned long long)b_coeff_bits | (1LL << 23); // add implicit 24th bit

    unsigned long long c = 0;

    // perform regular multiplication
    for(int bit = 0; bit < 24; bit++)
    {
        if (a24 & (1LL<<bit))
        {
            c += b24 << bit;
        }
    }

    // result can be 47 or 48 bit wide ie (and have 46th or 47th bit set)
    // shift coefficient/significand to the right place
    if (c & (1LL << 47))
    {
        c >>= 47 - 23;
    }
    else if (c & (1LL << 46))
    {
        c >>= 46 - 23;
    }

    c &= ~(1<<23); // clear 24th bit (implicitly stored)

    int c_exp_val = a_exp_val + b_exp_val + 1;
    if ((c_exp_val >= 0xff) || (c_exp_val <= 0))
    {
        // ble - NaN?
    }

    int c_exp_bits = ((c_exp_val + 127) & 0xFF) << 23;
    int c_sign_bit = (a_bits & (1<<31)) ^ ((b_bits & (1<<31)));

    int ret = c_sign_bit | c_exp_bits | (int)c; 

    return *((float*)&ret);
}

不完美,但似乎可以胜任。