在C语言中实现不使用运算符的浮点数IEEE754格式的乘法和除法

4

我需要一些关于编程的帮助。 我必须编写一个程序,它可以在没有运算符的情况下进行除法和乘法,并包含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

2
什么阻止你调试你的代码? - Paul R
我承认我没有读其他任何东西,但至少你正在用浮点数(%f)读取十六进制数字(0x...)。 - Adriano Repetti
是的,我知道这个问题,我尝试了各种选项来查看结果,最后只是复制了最新版本,但那是错误的。 - Lyzy
还有很多工作要做。首先:读取并打印浮点数。然后是mult()函数。while()循环不够用。float类型的值不一定总是整数,而你的循环却依赖于整数值。 - chux - Reinstate Monica
2
我在你的代码中看到了几个 * 运算符。那么 log/pow 的调用呢? - Klas Lindbäck
显示剩余3条评论
1个回答

2

仅供娱乐(请勿点踩)。这段代码遵守任务中所提出的规则;即不使用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);
}

不完美但似乎可以胜任工作。

喜欢你的第一个解决方案 :) - bolov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接