Liczenie pierwiastka kwadratowego do x miejsca po przecinku

0

Mam napisać program liczący metodą Newtona pierwiastek kwadratowy. Z uwagi na zakresy liczb musze uzywac BigDecimal.

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        int n = liczbaPierwiastkowana();
        int k = dokladnosc();
        BigDecimal x = BigDecimal.valueOf(1);
        BigDecimal a = BigDecimal.valueOf(n);

        do {
            x = ((x.add(a.divide(x))).multiply(BigDecimal.valueOf(0.5)));
            System.out.println(x);
        } while (0 < x.setScale(k, BigDecimal.ROUND_DOWN).multiply(x.setScale(k, BigDecimal.ROUND_DOWN)).compareTo(a));
        System.out.println(x);
    }

    static int liczbaPierwiastkowana() {
        Scanner scan = new Scanner(System.in);
        int n;
        do {
            System.out.println("Podaj liczbę z której chcesz wyciągnąć pierwiastek - liczbę całkowitą nieujemną, nie większą niż miliard:");
            n = scan.nextInt();
        } while (n < 0 || n > 1000000000);
        return n;
    }

    static int dokladnosc() {
        Scanner scan = new Scanner(System.in);
        int k;
        do {
            System.out.println("Podaj żądąną dokładność wyniku - liczbę całkowitą nieujemną, nie większą niż 10 000.");
            k = scan.nextInt();
        } while (k < 0 || k > 10000);
        return k;
    }

Tutaj blad po uruchomieniu:

Podaj liczbę z której chcesz wyciągnąć pierwiastek - liczbę całkowitą nieujemną, nie większą niż miliard:
50
Podaj żądąną dokładność wyniku - liczbę całkowitą nieujemną, nie większą niż 10 000.
10
25.5
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.base/java.math.BigDecimal.divide(BigDecimal.java:1722)
at Main.main(Main.java:14)

Dodatkowo intellij skresla mi set scale i round down, nie bardzo rozumiem dlaczego.

Prosze o wyrozumialosc i dziekuje za pomoc!

0
hesl napisał(a):

Dodatkowo intellij skresla mi set scale i round down, nie bardzo rozumiem dlaczego.

Jeśli intellij skreśla to znaczy, że metoda jest oznaczona adnotacją Deprecated. Której Javy używasz? W Javie 11 wiele rzeczy z klasy BigDecimal zostało oznaczonych jako przestarzałę i możliwe, że niedługo zostają wycofane. JavaDoc twoim przyjacielem

1

Wyobraź sobie, że kazałeś programowi policzyć 1 / 3 - jaki wynik powinien podać: 0.3, 0.33333, 0.33333333333333333333333, ...?

Dlatego też przy dzieleniu powinieneś określić skalę oraz sposób zaokrąglenia (https://jaydeepm.wordpress.com/2009/06/04/bigdecimal-and-non-terminating-decimal-expansion-error/).

2

Możesz ominąć to setScale, jak w ogóle to daje pewność poprawnego wyniku, i zamienić dokładność w ilości miejsc po przecinku, na ułamek: 0.1 dla 1, 0.001 dla 3, itd. To daje gwarancję precyzji (sprawdzamy różnice wartości bezwzględnych). I Używaj dokładności i zaokragleń i Potestuj to dokładnie, bo to też takie w sumie dość luźne rozumowanie:), acha acc biorę w miejscach po przecinku, czyli dla acc, podanego 1, wymagam sqrt(2) = 1.4.
Pierwiastek z dwóch: https://apod.nasa.gov/htmltest/gifcity/sqrt2.1mil

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
class Main {
  static BigDecimal ONE = new BigDecimal(1);
  static BigDecimal HALF = new BigDecimal("0.5");

  static void squareNewton(int n, int acc) {
    if (acc == 0) { // no accuracy
      System.out.println(ONE);
      return;
      }
    BigDecimal e = ONE.divide(new BigDecimal(10).pow(acc), acc + 1, RoundingMode.CEILING);
    BigDecimal x = new BigDecimal(0);
    BigDecimal x0 = ONE;
    BigDecimal a = new BigDecimal(n);
    for(int i = 0;;++i) {
        x = HALF.multiply(x0.add(a.divide(x0, acc, RoundingMode.HALF_DOWN)), new MathContext(acc + 1));
        if (x.subtract(x0).abs().compareTo(e) < 0) {
          System.out.println("Squrt value of " + n + " is " + x + " ");
          System.out.print("with "+  acc + " digits accuracy. ");
          System.out.println("After " + i + " iterations");
          break;
        }
        x0 = x;
    }
  } 
  public static void main(String[] args) {
    squareNewton(2, 1000000);
  }
}
0
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Scanner;

public class Main {


    static BigDecimal ONE = BigDecimal.valueOf(1);
    static BigDecimal HALF = BigDecimal.valueOf(0.5);

    public static void main(String[] args) {
        pierwiastkuj(liczbaPierwiastkowana(), dokladnosc());
    }

    private static void pierwiastkuj(int liczbaPierwiastkowana, int dokladnosc) {

        BigDecimal q = ONE;
        for (int i = 0; i < dokladnosc; i++) {
            q = q.divide(new BigDecimal(10), dokladnosc + 1, RoundingMode.DOWN);
        }

        BigDecimal x;
        BigDecimal x0 = ONE;
        BigDecimal a = new BigDecimal(liczbaPierwiastkowana);

        for(int i = 0;;++i) {
            x = HALF.multiply(x0.add(a.divide(x0, dokladnosc, RoundingMode.DOWN)), new MathContext(dokladnosc + 1, RoundingMode.DOWN));
            if (x.subtract(x0).abs().compareTo(q) < 0) {
                System.out.println();
                System.out.print("Pierwiastek z " + liczbaPierwiastkowana + " wynosi " + x + " ");
                System.out.println("z dokladnoscia "+  dokladnosc + " liczb po przecinku, ");
                System.out.println("Program iterował " + i + " razy.");
                break;
            }
            x0 = x;
        }
    }
    static int liczbaPierwiastkowana() {
        Scanner scan = new Scanner(System.in);
        int n;
        do {
            System.out.println("Podaj liczbę z której chcesz wyciągnąć pierwiastek - liczbę całkowitą nieujemną, nie większą niż miliard:");
            n = scan.nextInt();
        } while (n < 0 || n > 1000000000);
        return n;
    }

    static int dokladnosc() {
        Scanner scan = new Scanner(System.in);
        int k;
        do {
            System.out.println("Podaj żądąną dokładność wyniku - liczbę całkowitą nieujemną, nie większą niż 10 000.");
            k = scan.nextInt();
        } while (k < 0 || k > 10000);
        return k;
    }
}

Dzieeeeki!
Nie moge w zadaniu uzywac .pow, i zaokraglac musze w dół, wiec troche to zmienilem.

I mam jeszcze kilka pytań, w programie ktory napisales przy deklaracji e

BigDecimal e = ONE.divide(new BigDecimal(10).pow(acc), acc + 1, RoundingMode.CEILING);

skala, zamiast acc+1 moglaby byc acc, a rounding mode moglby byc jakikolwiek i wszystko byloby ok?

x = HALF.multiply(x0.add(a.divide(x0, acc, RoundingMode.HALF_DOWN)), new MathContext(acc + 1));

I tutaj, nie rozumiem czemu bez MathContext, x to nie jest prawidlowy wynik, jesli podalismy acc, i RoundingMode zmienilbym na DOWN.

0

skala, zamiast acc+1 moglaby byc acc, a rounding mode moglby byc jakikolwiek i wszystko byloby ok?

Wydawało mi sie, że jest niedokladnie przy jeden, nie kosztuje wiele

I tutaj, nie rozumiem czemu bez MathContext, x to nie jest prawidlowy wynik, jesli podalismy acc, i RoundingMode zmienilbym na DOWN.

MathContext jest do mnożenia, a ten rounding, to nie wiem czy ma znaczenie...

0 użytkowników online, w tym zalogowanych: 0, gości: 0