Android Question how do i sqrt accurately?

hi
i have written the following piece of code:
B4X:
Dim pi As BigDecimal
    pi.Initialize(0)
    Dim b As BigDecimal
    Dim c As BigDecimal
    c.Initialize(0)
    b.Initialize(0)
    Dim t As Long
    t=DateTime.Now
    For i=1 To 1000000
        c.Initialize(i)
        c.Multiply(c)
        b.Initialize(1)
        b.Divide2(c,100,0)
        pi.Add(b)
    Next
    c.Initialize(6)
    pi.Multiply(c)
    Log(pi)
    Log(DateTime.Now-t)
i used the "big numbers" library to get some accurate results
at the end the program logs pi squared, and i need to square-root it accurately, but with the core options in b4x i don't think that's possible.
i tried using the same "big numbers" library to do that but it seems that it doesn't have a sqrt function
i even tried using "pow" in that library which is the equivalent of power in core, i thought i could take it to the power of 0.5 which should be the equivalent of sqrt, but "pow" only accepts integers as an input and 0.5 is floating
.
any ideas what i should do?
 

Brian Dean

Active Member
Licensed User
Longtime User
any ideas what i should do?

If nobody else has a better idea, how about calculating the square root yourself? The algorithm is not very complicated - you start with a guess, divide your number by that guess, and the average of the result and the guess is a better approximation to the square root. Continue until you reach the required accuracy ...
B4X:
Sub squareRoot(number As Double) As Double
    Dim guess As Double = number / 2    ' Start with a wild guess
    Dim result As Double
    Dim error As Double = 1.0
    Do While (error > 0.000000001)        ' Set error at any preferred value
        result = number / guess
        error = Abs(guess - result)            ' How close have we got?
        guess = (guess + result) / 2    ' Use average of this guess and result 
    Loop
    Return guess
End Sub
Given the value PI this algoritm returns ...
1.5707963267948966
1.7853981633974483
1.7725007746756094
1.772453851526627
1.7724538509055159
1.772453850905516
 
Last edited:
Upvote 0

drgottjr

Well-Known Member
Licensed User
Longtime User
not sure what the issue is with b4a's sqrt method, but it you want java's sqrt() from java.lang.Math, you can do what's in the attached. i did it with b4j and the bigdecimal library because it's easier to throw together. should build easily enough with b4a

i don't know what a bigdecimal is, but it wasn't too difficult to use the library in conjunction with java's sqrt() method, as if it were included in the library (which is, judging by looking at the code, based on various facets of the java.lang.Match class. you can pass a normaldecimal to the call or - as i did - pass a bigdecimal's value (a bigdecimal is an object).

b4j happens to have a PI constant, so i used it for testing. the sqrt returned was 1.7724538509055159 (which looks like something shown in a previous answer).
 

Attachments

  • capture.png
    capture.png
    8.5 KB · Views: 167
Upvote 0

Mahares

Expert
Licensed User
Longtime User
not sure what the issue is with b4a's sqrt method
I am like you. I am not sure what the issue is either, but I used your javaobject method and the normal B4A sqrt function. Both yield the same result.
B4X:
Dim jo As JavaObject
    jo.InitializeStatic("java.lang.Math")
    Log(jo.RunMethod("sqrt",Array(cPI))) '1.7724538509055159
    Log(Sqrt(cPI)) '1.7724538509055159
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
but with the core options in b4x
Technically nothing to do with B4X (B4A in this case) since square root method for BigDecimal was not added until Java 9 (https://www.geeksforgeeks.org/bigdecimal-sqrt-method-in-java-with-examples/). Adapting @Brian Dean's answer may be the way forward (and is similar to this stackoverflow answer on the subject: https://stackoverflow.com/a/19743026).
not sure what the issue is with b4a's sqrt method, but it you want java's sqrt() from java.lang.Math, you can do what's in the attached.
Both yield the same result.
Neither work on BigDecimal
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Dies the example in Post#2 work on BigDecimal?
It would need to be rewritten to use BigDecimal numbers instead of Double's. BTW, I was somewhat incorrect in stating that @drgottjr would not work on BigDecimal. What it does is convert a BigDecimal to Double and then use the sqrt method of the math library. Ok, that works, but defeats the whole purpose of BigDecimal, since for really big numbers, even Double becomes very imprecise.
 
Upvote 0

drgottjr

Well-Known Member
Licensed User
Longtime User
sigh. apparently java's sqrt() of a bigdecimal doesn't work until java 9. passing a bigdecimal's.doublevalue to sqrt() may or may not accomplish anything special. in other words, the sqrt() of a bigdecimal isn't in the library because it didn't exist. there are numerous formulae around, like what appears above where you can set your scale of precision. sorry i poke my nose in.
 
Upvote 0

drgottjr

Well-Known Member
Licensed User
Longtime User
i changed my mind. see if this works for you:

B4X:
'put this in main:
    Dim jo as JavaObject
    jo.initializeContext
    Dim scale As Int = 200        ' scale to fit
    dim somebigdecimal as string = "4"       ' put your bigdecimal here
    Dim bdstring As String = jo.RunMethod("bdsqrt", Array(somebigdecimal,scale))
    Log(bdstring)   

'=========================================================
'tack this onto your project:

#if Java
   import java.lang.Math;
   import java.math.BigDecimal;
   import java.math.BigInteger;
   import java.math.MathContext;
   import java.math.RoundingMode;
 
   public static String bdsqrt(String strparam, int SCALE) {
     BigDecimal A = new BigDecimal( strparam );
     final BigDecimal TWO = BigDecimal.valueOf(2);
     BigDecimal x0 = new BigDecimal("0");
     BigDecimal x1 = new BigDecimal(Math.sqrt(A.doubleValue()));
     while (!x0.equals(x1)) {
         x0 = x1;
         x1 = A.divide(x0, SCALE, 4);
         x1 = x1.add(x0);
         x1 = x1.divide(TWO, SCALE, 4);
    }

    return x1.toPlainString();
}
#End If

i found the function on stackoverflow. had to modify entry and exit to get it to work with b4x (the library's bigdecimal is not the same as java's, and i didn't want to spend the time modifying the code even more). the actual heavy work is exactly as found. it gave me answers i was expecting in the few tests i ran.
 
Upvote 0

drgottjr

Well-Known Member
Licensed User
Longtime User
sqrt, primes, etc. not my thing. i can connect b4x with java for those who cannot, so i thought i could help in that way. still unclear. we'll see if originator chimes in. thanks anyway
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
The library's bigdecimal is not the same as java's
It is!
Java:
import java.math.BigDecimal;
import java.math.BigInteger;
//....
public BigDecimal bigd;
But it is wrapped. You can get /set the BigDecimal instance from the bigd field which could tidy your Java up a bit.

EDIT: BigInteger is also wrapped and has a corresponding bigi field
 
Last edited:
Upvote 0

mading1309

Member
Licensed User
Longtime User
Hello

In general x^y can be expressed as exp(yln(x)).
Now you can express your sqrt, set y=0.5, as exp (0.5 ln(x))
I don't know about the following errors of ln and exp computation

May be it's helpful
Mading
 
Upvote 0
Top