简体   繁体   English

如何使用BigDecimal递增for循环?

[英]How do I increment a for loop using BigDecimal?

So I'm more or less a noob when it comes to coding. 因此,在编码方面,我或多或少是菜鸟。 I'm learning java for a university course, and one of my exercises requires me to write a code that evaluates an integral using the left endpoint method, midpoint method and the trapezium method. 我正在为大学课程学习Java,我的一项练习要求我编写一个代码,该代码使用左端点方法,中点方法和梯形方法对整数进行求值。

For this I need to use a for loop that increments by one step each time. 为此,我需要使用一个for循环,该循环每次递增一个步骤。 I know how to do this just using double, but the problem is, when I'm running calculations using the double data type, it gives me rounding errors. 我知道仅使用double即可执行此操作,但是问题是,当我使用double数据类型运行计算时,会产生舍入错误。 After reading up (mostly looking at other stack overflow questions), I figured I should use BigDecimal to remove the rounding error. 阅读完之后(主要是查看其他堆栈溢出问题),我认为我应该使用BigDecimal消除舍入错误。

However using BigDecimal gives me a whole bunch of errors. 但是,使用BigDecimal会给我带来很多错误。 From what I can tell, I can't use normal operators such as <, >, == etc, because BigDecimal is not a primitive data type. 据我所知,我不能使用<,>,==等常规运算符,因为BigDecimal不是原始数据类型。 But then I don't know how to do a basic for loop that increments whilst still using BigDecimal. 但是然后我不知道如何在仍然使用BigDecimal的同时进行递增的基本for循环。 Another thing I looked at here suggested using Commons-math? 我在这里看到的另一件事建议使用Commons-math? (second answer down) (第二答案)

https://stackoverflow.com/questions/16707397/whats-wrong-with-this-simple-double-calculation# = https://stackoverflow.com/questions/16707397/whats-wrong-with-this-simple-double-calculation# =

I don't have the faintest idea how to use this as, as far as I can tell, it's not similar to just plain old import java.lang.Math for example. 据我所知,我不知道如何使用它,这与例如普通的老式导入java.lang.Math不一样。

So I guess my question is, how can I get my code to work using BigDecimal in a for loop, and in comparing numbers together generally, or how can I use Common-Math to simply avoid the rounding error altogether? 所以我想我的问题是,如何才能在for循环中使用BigDecimal来使我的代码正常工作,以及如何将数字进行一般比较,或者我如何才能使用Common-Math来完全避免舍入错误?

Here is my code: 这是我的代码:

import java.util.Scanner;
import java.lang.Math;
import java.math.BigDecimal;

public class IntegrationMethods{

  //calculates the value of the function f(x)=x^2
  public static BigDecimal f(BigDecimal x){
    return x.multiply(x);
  }

  //uses a, b and N as arguments, calculates sum of integral using left 
endpoint rule
  public static BigDecimal leftEndpoint(BigDecimal a, BigDecimal b, 
BigDecimal n){
    BigDecimal h = (b.subtract(a)).divide(n);
    sum = new BigDecimal("0");
    i = new BigDecimal("0");
    for(i.compareTo(n)<=0;){
      sum = sum.add(h.multiply(f(a.add(h.multiply(i-1)))));
      i = i.add(new BigDecimal(1));
    }
    return sum;
  }

  public static BigDecimal midpoint(BigDecimal a, BigDecimal b, BigDecimal 
n){
    BigDecimal h = (b.subtract(a)).divide(n);
    BigDecimal sum = 0.0;
    for(BigDecimal i=0.0; i<n; i++){
      BigDecimal x1 = a.add(h.multiply(i));
      BigDecimal x2 = a.add(h.multiply(i+1));
      sum = sum.add(h.multiply((f(x1).add(f(x2))).divide(2)));
    }
    return sum;
  }

  public static void main(String[] args){
    Scanner scanner = new Scanner(System.in);

System.out.println("Please enter the lower limit of integration a.");
BigDecimal a = scanner.nextBigDecimal();

System.out.println("Please enter the upper limit of integration b.");
BigDecimal b = scanner.nextBigDecimal();

//swaps a and b so that the bigger of the two is always b.
//this prevents a negative popping up later on.
if(b<a){
  BigDecimal r = a;
  BigDecimal m = b;
  a = m;
  b = r;
}

System.out.println("Please enter the number of sampling points N.");
BigDecimal n = scanner.nextBigDecimal();

//checks if n is greater than or equal to 1, and asks for a new value if it isn't.
while (n<1.0){
  System.out.println("Please enter a new value for N.");
  n = scanner.nextBigDecimal();
}

System.out.println("For " + n + " intervals, the integral of x^2 using the left endpoint rule is: " + leftEndpoint(a,b,n));
System.out.println("Using the midpoint rule, the integral of x^2 is: " + midpoint(a,b,n));
  }
}

A normal loop to count from 0 to 19 is: 从0到19计数的普通循环为:

for (int i = 0; i < 20; i++)
    System.out.println(i);

The same loop done using BigDecimal looks like this: 使用BigDecimal完成的相同循环如下所示:

BigDecimal end = BigDecimal.valueOf(20);
for (BigDecimal i = BigDecimal.ZERO; i.compareTo(end) < 0; i = i.add(BigDecimal.ONE))
    System.out.println(i);

The way to use < , > , == etc with BigDecimal , is to use the compareTo() method. BigDecimal使用<>==等的方法是使用compareTo()方法。 The javadoc shows how to do this: Javadoc显示了如何执行此操作:

This method is provided in preference to individual methods for each of the six boolean comparison operators (<, ==, >, >=, !=, <=). 对于六个布尔比较运算符(<,==,>,> =,!=,<=)中的每一个,该方法优先于单个方法提供。 The suggested idiom for performing these comparisons is: (x.compareTo(y) <op> 0) , where <op> is one of the six comparison operators. 建议执行这些比较的惯用法是: (x.compareTo(y) <op> 0) ,其中<op>是六个比较运算符之一。

So, i < end is written as i.compareTo(end) < 0 . 因此, i < end被写为i.compareTo(end) < 0

Also notice that BigDecimal has predefined constants for 0 , 1 , and 10 ( BigDecimal.ZERO , BigDecimal.ONE , and BigDecimal.TEN ), and that creating BigDecimal integer values should use BigDecimal.valueOf(long val) , rather than new BigDecimal(String val) . 还要注意, BigDecimal具有预定义的常数01 ,和10BigDecimal.ZEROBigDecimal.ONE ,和BigDecimal.TEN ),并且创建BigDecimal整数值应该使用BigDecimal.valueOf(long val)而不是new BigDecimal(String val)

Each piece of a for loop can have any expression you desire. 每个for循环都可以具有您想要的任何表达式。 The first one initializes a variable, the second must evaluate to a boolean, and the third is any expression. 第一个初始化变量,第二个必须求值布尔值,第三个是任何表达式。 So for example: 因此,例如:

for (BigDecimal i = BigDecimal.ZERO; i.compareTo(n) < 0; i = i.add(BigDecimal.ONE)) {
}

It is a bad idea to use a floating point value like BigDecimal as a loop counter as it can lead to unexpected behavior. 使用BigDecimal类的浮点值作为循环计数器是一个坏主意,因为它可能导致意外行为。 You can read more about that here: https://www.securecoding.cert.org/confluence/display/java/NUM09-J.+Do+not+use+floating-point+variables+as+loop+counters 您可以在此处阅读有关此内容的更多信息: https : //www.securecoding.cert.org/confluence/display/java/NUM09-J.+Do+not+use+floating-point+variables+as+loop+counters

If you make your for-loop counter of type int , you can just wrap it in a new BigDecimal instance to pass to h.multiply() and yield the expected result: 如果您将in-for计数器设为int类型,则可以将其包装在新的BigDecimal实例中,以传递给h.multiply()并产生预期的结果:

for(int i=0; BigDecimal.of(i).compareTo(n) < 0; i++){
  BigDecimal x1 = a.add(h.multiply(BigDecimal.of(i)));
  BigDecimal x2 = a.add(h.multiply(BigDecimal.of(i+1)));
  sum = sum.add(h.multiply((f(x1).add(f(x2))).divide(2)));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM