C - 大数乘后后的错误输出

时间:2017-08-20 03:53:13

标签: c double multiplication

我正在为 n 实施我自己的减少和征服方法。

这是程序:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>

double dncpow(int a, int n)
{
    double p = 1.0;
    if(n != 0)
    {
        p = dncpow(a, n / 2);
        p = p * p;
        if(n % 2)
        {
            p = p * (double)a;
        }
    }
    return p;
}

int main()
{
    int a;
    int n;
    int a_upper = 10;
    int n_upper = 50;
    int times = 5;
    time_t t;
    srand(time(&t));
    for(int i = 0; i < times; ++i)
    {
        a = rand() % a_upper;
        n = rand() % n_upper;
        printf("a = %d, n = %d\n", a, n);
        printf("pow = %.0f\ndnc = %.0f\n\n", pow(a, n), dncpow(a, n));
    }
    return 0;
}

我的代码适用于a和n的小值,但是对于诸如以下的输入,会观察到pow()和dncpow()的输出不匹配:

a = 7,n = 39

pow = 909543680129861204865300750663680

dnc = 909543680129861348980488826519552

我非常确定算法是正确的,但是dncpow()给了我错误的答案。 有人可以帮我纠正这个吗?提前谢谢!

1 个答案:

答案 0 :(得分:2)

很简单,这些数字对于您的计算机可以在单个变量中准确表示的数字来说太大了。对于浮点类型,有一个指数单独存储,因此仍然可以表示接近实数的数字,删除尾数的最低位。

关于this comment

  

将'double'替换为'long long'时,我得到类似的输出。后者应该准确存储,不是吗?

  • 如果您使用public void showDialog(EditText ed){ final EditText e = ed; e.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { final Calendar c = Calendar.getInstance(); int mYear = c.get(Calendar.YEAR); // current year int mMonth = c.get(Calendar.MONTH); // current month int mDay = c.get(Calendar.DAY_OF_MONTH); // current day dpd = new DatePickerDialog(getActivity(), new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(DatePicker datePicker, int year, int monthOfYear, int dayOfMonth) { e.setText(dayOfMonth + " / "+ (monthOfYear+1) + " / " + year); } },mYear,mMonth,mDay); dpd.show(); } }); } 来调用某个功能,则 不会在double上进行操作。您的价值只是转换为long long,您只会获得相同的结果。
  • 即使使用函数处理double(在现今的典型平台上有64位),也无法处理如此大的数字。 64位不足以存储它们。使用 unsigned 整数类型,它们只会在溢出时“环绕”到long long。使用 signed 整数类型时,溢出的行为是未定义(但仍有可能是回绕)。所以你会得到一些与预期结果完全无关的数字。这可能比使用浮点类型的结果更糟糕,那只是不精确

对于大数字的精确计算,唯一的方法是将它们存储在数组(通常是无符号整数,如0)中,并自行实现所有算术。这是一个很好的练习,并且很多的工作,尤其是在对性能感兴趣时(“天真”算术算法通常非常低效)。

对于一些真实的程序,你不会在这里重新发明轮子,因为有用于处理大数字的库。可以说是最着名的是libgmp。阅读那里的手册并使用它。