Can we compute the square root of a BigDecimal
in Java by using only the Java API and not a custom-made 100-line algorithm?
相关问题
- Delete Messages from a Topic in Apache Kafka
- Jackson Deserialization not calling deserialize on
- How to maintain order of key-value in DataFrame sa
- StackExchange API - Deserialize Date in JSON Respo
- Difference between Types.INTEGER and Types.NULL in
As it was said before: If you don't mind what precision your answer will be, but only want to generate random digits after the 15th still valid one, then why do you use BigDecimal at all?
Here is code for the method that should do the trick with floating point BigDecimals:
As a test, try to repeatedly square a number a couple of times than taking the repeated square root, and see how close you are from where you started.
I came up with an algorithm that doesn't just take the square root, but does every root below an integer of every BigDecimal. With the big advantage that it doesn't do a search algorithm, so it's quite fast with a 0,1ms - 1ms runtime.
But what you get in speed and versatility, it lacks in accuracy, it averages 5 correct digits with a deviancy of 3 on the fifth digit. (Tested with a million random numbers and roots), although the test ran with very high roots, so you can expect a bit more accuracy if you keep the roots below 10.
The result only holds 64 bits of precision, with the rest of the number being zeroes, so if you need very high levels of precision, don't use this function.
It's made to handle very large numbers, and very large roots, not very small numbers.
It works by using a mathematical property that basicly says when you are doing square roots you can change x^0.5 to (x/100)^0,5 * 10 so divide the base by 100 take the power and multiply by 10.
Generalized it becomes x^(1/n) = (x / 10^n) ^ (1/n) * 10.
So for cube roots you need to divide the base by 10^3, and for quad roots you need to divide with 10^4 and so on.
The algorithm uses that functions to scale the input down to something the math library can handle and then scale it back up again based how much the input was scaled down.
It also handles a few edge cases where the input can't be scaled down enough, and it's those edge cases that adds a lot of the accuracy problems.
As of Java 9 you can! See
BigDecimal.sqrt()
.By using Karp's Tricks, this can be implemented without a loop in only two lines, giving 32 digits precision:
There isn't anything in the java api, so if double is not accurate enough (If not, why use BigDecimal at all?) then you need something like the below code.)
From http://www.java2s.com/Code/Java/Language-Basics/DemonstrationofhighprecisionarithmeticwiththeBigDoubleclass.htm
I've used this and it works quite well. Here's an example of how the algorithm works at a high level.
Edit: I was curious to see just how accurate this was as defined below. Here is the sqrt(2) from an official source:
and here it is using the approach I outline below with
SQRT_DIG
equal to 150:The first deviation occurs after 195 digits of precision. Use at your own risk if you need such a high level of precision as this.
Changing
SQRT_DIG
to 1000 yielded 1570 digits of precision.be sure to check out barwnikk's answer. it's more concise and seemingly offers as good or better precision.