由方法返回的长整型分割 - 错误值

3

我有两种方法:幂和阶乘:

public static long pow(int x, int n) {
    long p = x;
    for (int i = 1; i < n; i++) {
        p *= x;
    }
    return p;
}

public static long fact(int n) {
    long s = n;
    for (int i = 1; i < n; i++ ) {
        s *= i;
    }
    return s;
}

这些返回 longs 的方法在我想要用它们计算指数函数时,与Math.exp(x)的结果不同。我的代码如下:

public static void exp(int x, double eps) {
    int i = 1;
    double pow = 1.0;
    double fact = 1.0;
    double sum = 0.0;
    double temp;
    do {
        temp = pow/fact;
        sum += temp;
        pow = pow(x, i);
        fact = fact(i);
        i++;
    }
    while (temp > eps);
    System.out.println("Check: " + Math.exp(x));
    System.out.println("My: " + sum);
}

public static void main() {
    int x = 10;
    double eps = 0.0000000000001;

    exp(x, eps);
}

当 x=10 时的输出如下:

检查:22026.465794806718

我的:21798.734894914145

x 越大,“精度损失”就越大(并不完全准确,因为你不能真正称之为精确...)。

问题在于,当方法 powerfactorial 返回 double 时,输出结果才是正确的。有人能告诉我如何使其正常工作吗?

方法 powfact 必须返回 long,并且我必须在 exp 中使用它们(这是一项大学任务)。

3个回答

3

如果您尝试使用这个pow方法:

public static long pow(int x, int n) {
    long p = x;
    System.out.println("Pow: "+x+","+n);
    for (int i = 1; i < n; i++) {
        p *= x;
        System.out.println(p);
    }
    return p;
}

您会得到以下输出:
...
Pow: 10,20
100
1000
10000
...
...
1000000000000000
10000000000000000
100000000000000000
1000000000000000000
-8446744073709551616
7766279631452241920

长整型数值溢出: 10^20 太大了,无法存储在长整型中。

powfact 方法必须返回长整型,并且我必须在 exp 中使用它们(学校作业)。

那么你没有太多办法来解决这个问题。如果 eps 太小,你可以抛出一个异常。


哇,你说得对。在这种情况下,long 的范围比正常的 double 要小,这对我来说有点奇怪...谢谢。 - hodak
@hodak - 你是什么意思?long类型的范围比double类型小(约为2^63),这是什么意思? - Ishtar
两个函数都可能溢出,取决于参数的大小 - pow()增长得更快。 您可以使用BigDecimal并检测情况,但几乎无法将结果适合长整型。 - Rostislav Matl

0

长整型无法处理小数精度,这就是为什么使用长整型时您的值会出错。为什么不让函数返回双精度值呢?

编辑:这是我想到的:

  public static long pow(int x, int n) 
  {
    double p = x;
    for (int i = 1; i < n; i++) {
      p *= x;
    }
    return (long)p;
  }

  public static long fact(int n) 
  {
    double s = n;
    for (int i = 1; i < n; i++ ) {
      s *= i;
    }
    return (long)s;
  }


  public static void exp(int x, double eps) 
  {
    double pow = 1.0;
    double fact = 1.0;
    double sum = 0.0;
    double temp;
    for(int ii=1; ii < 100; ii++)
    {
      pow = pow(x, ii);
      fact = fact(ii);
      temp = (double)pow/(double)fact;
      temp = temp == 1 ? 0 : temp;
      sum += temp;
    }

    System.out.println("Check: " + Math.exp(x));
    System.out.println("My: " + sum);
  }

  public static void main(final String[] args)
  {
    int x = 10;
    double eps = 0.0000000000001;

    exp(x, eps);
  }

如果不使用小数,那就是最接近的了。

Check: 22026.465794806718
My: 21946.785573087538

我不能这样做,我的任务要求使用long类型。但是当我尝试像这样转换时:'pow = (double)power(x, i)' 和 'fact = (double)fact(i)',我也无法进行强制类型转换。 - hodak
@hodak,你不能在赋值中使用double类型似乎很奇怪,你确定这是正确的吗? - Grammin
是的,他明确声明了,但有可能他这样做是为了迫使我们找到答案,为什么那不正确。好老师,这只花了我大约几个小时 ;) - hodak

0

x 通常有多大?可能是整数溢出。尝试将 powfact 中的所有 int 参数改为 long


x不是很大,它的范围是从1到20。将“int”更改为“long”也没有帮助。 - hodak

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