method is performing incorrect calculations on double argument - java

firstly, im sorry if this is a trivial question. I am a beginner and have been stuck on this for hours.
Below I have tried to create a unitizer method which has a series of if else statements. They are written in descending order, each time checking if a value can be divided by a given number, and if so, performing a division, rounding the value and adding an appropriate unit to the result.
in this question I have attempted to remove all unnecessary code, thus what i am presenting here is only a fragment of the unitizer method.
why is the unitizer method outputting values in hours, when the value should be in seconds?
For clarification, the expected value is ~ 4 seconds.
public class simplified
{
public static void main(String[] args)
{
int i = 5;
double n = Math.pow(2, (double) i);
System.out.println(a6(n)); // correctly displays the expected value.
System.out.println(unitizer(a6(n)));
}
public static double a6 (double n)
{
return Math.pow(2, n); // this value is in nanoseconds.
}
public static String unitizer (double x)
{
String time = "";
if (x/(60*60*1000*1000*1000) >= 1)
{
x = Math.round(x/(60*60*1000*1000*1000) * 100.0) / 100.0;
time = x + "hr ";
}
return time;
}
}
console output:
4.294967296E9
5.25hr

There is an int overflow at the expression 60*60*1000*1000*1000. This means, that the actual result 3,600,000,000,000 is too large to be stored as an int value and is therefore 'reduced' (mod 2^31) to 817,405,952.
This can be fixed by evaluating said expression in a 'larger' arithmetic, e.g. long. There is a nice little modifier, that will force exactly that:
60L*60*1000*1000*1000
^
In particular, it hints the compiler to interpret the preceding literal 60 as a long value and in consequence the whole calculation will be done in long arithmetic.
This modifier is by the way case-insensitive; however I prefer an upper-case L, because the lower-case letter l can easily be mistaken by the number 1.
With this change, the code will not enter the if-statement, because the value x is not larger than one hour. Most probably the omitted code of unitizer will deal with this case.
On a last side note, java has an in-built TimeUnit enum, which can do these conversions, too. However, it does so in long arithmetic and not in double arithmetic as it is required for this specific question.

Related

Why am I seeing a one-off error with Math.pow(11, 16)?

I have to compute 11^16 for a project at my Uni. Somehow Math.pow(11,16) computes a solution exactly 1 less than WolframAlpha or my other computation method.
My code is:
public class Test {
public static void main(String args[]) {
long a = 11;
long b = 16;
System.out.println("" + (long)Math.pow(a, b));
System.out.println("" + squareAndMultiply(a, b));
}
public static long squareAndMultiply(long b, long e){
long result = 1;
long sq = b;
while(e>0){
if(e%2==1){
result *= sq;
}
sq = sq * sq;
e /= 2;
}
return result;
}
}
The result from the code is:
math.pow(11,16):
45949729863572160
squareAndMultiply(11,16):
45949729863572161
With floating-point arithmetic, you're in that gray zone where the precision of a double is less than that of a long (even if the range of a double is much bigger).
A double has 53 bits of precision, whereas a long can devote all 64 bits to precision. When you're dealing with values as high as 1116, the difference between one double value and the next one up becomes noticeable.
Java has a built-in method Math.ulp ("unit in last place") that effectively gives the difference in values between consecutive representable values. (There's a double version and a float version.)
System.out.println(Math.ulp(Math.pow(11, 16)));
8.0
That means the least possible double value greater than 45949729863572160 is 45949729863572168.
The long value 45949729863572161 is correct, but the value you're getting with Math.pow, 45949729863572160, is as close as a double can get to the true answer, given its limited (but still large) precision.
Casting to a long makes no difference, because Math.pow already computes the result as a double, so the answer is off by one already. Your long method of computing the value is correct.
If you're computing values that would overflow long, then instead of using double, you can use BigDecimal, which has its own pow method to retain a precision of 1.0.
The root cause of this discrepancy is loss of precision because of Double precision numbers are accurate up to sixteen decimal places.
One way to demonstrate is this example.
System.out.println((double)999999999999999999L);
outputs:
1.0E18
The output of Math.pow(11, 16) is 4.594972986357216E16, which on casting to long gets converted into 45949729863572160.
If you are interested more in learning about the loss of precision, you can check this.

Calculating sin function with JAVA BigDecimal -monomial is going bigger(?)

I'm making sin function with BigDecimal in JAVA, and this is as far as I go:
package taylorSeries;
import java.math.BigDecimal;
public class Sin {
private static final int cutOff = 20;
public static void main(String[] args) {
System.out.println(getSin(new BigDecimal(3.14159265358979323846264), 100));
}
public static BigDecimal getSin(BigDecimal x, int scale) {
BigDecimal sign = new BigDecimal("-1");
BigDecimal divisor = BigDecimal.ONE;
BigDecimal i = BigDecimal.ONE;
BigDecimal num = null;
BigDecimal result = x;
//System.err.println(x);
do {
x = x.abs().multiply(x.abs()).multiply(x).multiply(sign);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
num = x.divide(divisor, scale + cutOff, BigDecimal.ROUND_HALF_UP);
result = result.add(num);
//System.out.println("d : " + divisor);
//System.out.println(divisor.compareTo(x.abs()));
System.out.println(num.setScale(9, BigDecimal.ROUND_HALF_UP));
} while(num.abs().compareTo(new BigDecimal("0.1").pow(scale + cutOff)) > 0);
System.err.println(num);
System.err.println(new BigDecimal("0.1").pow(scale + cutOff));
return result.setScale(scale, BigDecimal.ROUND_HALF_UP);
}
}
It uses Taylor series :
picture of the fomular
The monomial x is added every iteration and always negative number.
And the problem is, absolute value of x is getting bigger and bigger, so iteration never ends.
Is there and way to find them or better way to implement it from the first place?
EDIT:
I made this code from scratch with simple interest about trigonometric functions, and now I see lots of childish mistakes.
My intention first was like this:
num is x^(2k+1) / (2k+1)!
divisor is (2k+1)!
i is 2k+1
dividend is x^(2k+1)
So I update divisor and dividend with i and compute num by sign * dividend / divisor and add it to result by result = result.add(num)
so new and good-working code is:
package taylorSeries;
import java.math.BigDecimal;
import java.math.MathContext;
public class Sin {
private static final int cutOff = 20;
private static final BigDecimal PI = Pi.getPi(100);
public static void main(String[] args) {
System.out.println(getSin(Pi.getPi(100).multiply(new BigDecimal("1.5")), 100)); // Should be -1
}
public static BigDecimal getSin(final BigDecimal x, int scale) {
if (x.compareTo(PI.multiply(new BigDecimal(2))) > 0) return getSin(x.remainder(PI.multiply(new BigDecimal(2)), new MathContext(x.precision())), scale);
if (x.compareTo(PI) > 0) return getSin(x.subtract(PI), scale).multiply(new BigDecimal("-1"));
if (x.compareTo(PI.divide(new BigDecimal(2))) > 0) return getSin(PI.subtract(x), scale);
BigDecimal sign = new BigDecimal("-1");
BigDecimal divisor = BigDecimal.ONE;
BigDecimal i = BigDecimal.ONE;
BigDecimal num = null;
BigDecimal dividend = x;
BigDecimal result = dividend;
do {
dividend = dividend.multiply(x).multiply(x).multiply(sign);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
num = dividend.divide(divisor, scale + cutOff, BigDecimal.ROUND_HALF_UP);
result = result.add(num);
} while(num.abs().compareTo(new BigDecimal("0.1").pow(scale + cutOff)) > 0);
return result.setScale(scale, BigDecimal.ROUND_HALF_UP);
}
}
The new BigDecimal(double) constructor is not something you generally want to be using; the whole reason BigDecimal exists in the first place is that double is wonky: There are almost 2^64 unique values that a double can represent, but that's it - (almost) 2^64 distinct values, smeared out logarithmically, with about a quarter of all available numbers between 0 and 1, a quarter from 1 to infinity, and the other half the same but as negative numbers. 3.14159265358979323846264 is not one of the blessed numbers. Use the string constructor instead - just toss " symbols around it.
every loop, sign should switch, well, sign. You're not doing that.
In the first loop, you overwrite x with x = x.abs().multiply(x.abs()).multiply(x).multiply(sign);, so now the 'x' value is actually -x^3, and the original x value is gone. Next loop, you repeat this process, and thus you definitely are nowhere near the desired effect. The solution - don't overwrite x. You need x, throughout the calculation. Make it final (getSin(final BigDecimal x) to help yourself.
Make another BigDecimal value and call it accumulator or what not. It starts out as a copy of x.
Every loop, you multiply x to it twice then toggle the sign. That way, the first time in the loop the accumulator is -x^3. The second time, it is x^5. The third time it is -x^7, and so on.
There is more wrong, but at some point I'm just feeding you your homework on a golden spoon.
I strongly suggest you learn to debug. Debugging is simple! All you really do, is follow along with the computer. You calculate by hand and double check that what you get (be it the result of an expression, or whether a while loop loops or not), matches what the computer gets. Check by using a debugger, or if you don't know how to do that, learn, and if you don't want to, add a ton of System.out.println statements as debugging aids. There where your expectations mismatch what the computer is doing? You found a bug. Probably one of many.
Then consider splicing parts of your code up so you can more easily check the computer's work.
For example, here, num is supposed to reflect:
before first loop: x
first loop: x - x^3/3!
second loop: x - x^3/3! + x^5/5!
etcetera. But for debugging it'd be so much simpler if you have those parts separated out. You optimally want:
first loop: 3 separated concepts: -1, x^3, and 3!.
second loop: +1, x^5, and 5!.
That debugs so much simpler.
It also leads to cleaner code, generally, so I suggest you make these separate concepts as variables, describe them, write a loop and test that they are doing what you want (e.g. you use sysouts or a debugger to actually observe the power accumulator value hopping from x to x^3 to x^5 - this is easily checked), and finally put it all together.
This is a much better way to write code than to just 'write it all, run it, realize it doesn't work, shrug, raise an eyebrow, head over to stack overflow, and pray someone's crystal ball is having a good day and they see my question'.
The fact that the terms are all negative is not the problem (though you must make it alternate to get the correct series).
The term magnitude is x^(2k+1) / (2k+1)!. The numerator is indeed growing, but so is the denominator, and past k = x, the denominator starts to "win" and the series always converges.
Anyway, you should limit yourself to small xs, otherwise the computation will be extremely lengthy, with very large products.
For the computation of the sine, always begin by reducing the argument to the range [0,π]. Even better, if you jointly develop a cosine function, you can reduce to [0,π/2].

Java double and working with really small values

I have to store the product of several probabilty values that are really low (for example, 1E-80). Using the primitive java double would result in zero because of the underflow. I don't want the value to go to zero because later on there will be a larger number (for example, 1E100) that will bring the values within the range that the double can handle.
So, I created a different class (MyDouble) myself that works on saving the base part and the exponent parts. When doing calculations, for example multiplication, I multiply the base parts, and add the exponents.
The program is fast with the primitive double type. However, when I use my own class (MyDouble) the program is really slow. I think this is because of the new objects that I have to create each time to create simple operations and the garbage collector has to do a lot of work when the objects are no longer needed.
My question is, is there a better way you think I can solve this problem? If not, is there a way so that I can speedup the program with my own class (MyDouble)?
[Note: taking the log and later taking the exponent does not solve my problem]
MyDouble class:
public class MyDouble {
public MyDouble(double base, int power){
this.base = base;
this.power = power;
}
public static MyDouble multiply(double... values) {
MyDouble returnMyDouble = new MyDouble(0);
double prodBase = 1;
int prodPower = 0;
for( double val : values) {
MyDouble ad = new MyDouble(val);
prodBase *= ad.base;
prodPower += ad.power;
}
String newBaseString = "" + prodBase;
String[] splitted = newBaseString.split("E");
double newBase = 0; int newPower = 0;
if(splitted.length == 2) {
newBase = Double.parseDouble(splitted[0]);
newPower = Integer.parseInt(splitted[1]);
} else {
newBase = Double.parseDouble(splitted[0]);
newPower = 0;
}
returnMyDouble.base = newBase;
returnMyDouble.power = newPower + prodPower;
return returnMyDouble;
}
}
The way this is solved is to work in log space---it trivialises the problem. When you say it doesn't work, can you give specific details of why? Probability underflow is a common issue in probabilistic models, and I don't think I've ever known it solved any other way.
Recall that log(a*b) is just log(a) + log(b). Similarly log(a/b) is log(a) - log(b). I assume since you're working with probabilities its multiplication and division that are causing the underflow issues; the drawback of log space is that you need to use special routines to calculate log(a+b), which I can direct you to if this is your issue.
So the simple answer is, work in log space, and re-exponentiate at the end to get a human-readable number.
You trying to parse strings each time you doing multiply. Why don't you calculate all values into some structure like real and exponential part as pre-calculation step and then create algorithms for multiplication, adding, subdivision, power and other.
Also you could add flag for big/small numbers. I think you will not use both 1e100 and 1e-100 in one calculation (so you could simplify some calculations) and you could improve calculation time for different pairs (large, large), (small, small), (large, small).
You can use
BigDecimal bd = BigDecimal.ONE.scaleByPowerOfTen(-309)
.multiply(BigDecimal.ONE.scaleByPowerOfTen(-300))
.multiply(BigDecimal.ONE.scaleByPowerOfTen(300));
System.out.println(bd);
prints
1E-309
Or if you use a log10 scale
double d = -309 + -300 + 300;
System.out.println("1E"+d);
prints
1E-309.0
Slowness might be because of the intermediate string objects which are created in split and string concats.
Try this:
/**
* value = base * 10 ^ power.
*/
public class MyDouble {
// Threshold values to determine whether given double is too small or not.
private static final double SMALL_EPSILON = 1e-8;
private static final double SMALL_EPSILON_MULTIPLIER = 1e8;
private static final int SMALL_EPSILON_POWER = 8;
private double myBase;
private int myPower;
public MyDouble(double base, int power){
myBase = base;
myPower = power;
}
public MyDouble(double base)
{
myBase = base;
myPower = 0;
adjustPower();
}
/**
* If base value is too small, increase the base by multiplying with some number and
* decrease the power accordingly.
* <p> E.g 0.000 000 000 001 * 10^1 => 0.0001 * 10^8
*/
private void adjustPower()
{
// Increase the base & decrease the power
// if given double value is less than threshold.
if (myBase < SMALL_EPSILON) {
myBase = myBase * SMALL_EPSILON_MULTIPLIER;
myPower -= SMALL_EPSILON_POWER;
}
}
/**
* This method multiplies given double and updates this object.
*/
public void multiply(MyDouble d)
{
myBase *= d.myBase;
myPower += d.myPower;
adjustPower();
}
/**
* This method multiplies given primitive double value with this object and update the
* base and power.
*/
public void multiply(double d)
{
multiply(new MyDouble(d));
}
#Override
public String toString()
{
return "Base:" + myBase + ", Power=" + myPower;
}
/**
* This method multiplies given double values and returns MyDouble object.
* It make sure that too small double values do not zero out the multiplication result.
*/
public static MyDouble multiply(double...values)
{
MyDouble result = new MyDouble(1);
for (int i=0; i<values.length; i++) {
result.multiply(values[i]);
}
return result;
}
public static void main(String[] args) {
MyDouble r = MyDouble.multiply(1e-80, 1e100);
System.out.println(r);
}
}
If this is still slow for your purpose, you can modify multiply() method to directly operate on primitive double instead of creating a MyDouble object.
I'm sure this will be a good deal slower than a double, but probably a large contributing factor would be the String manipulation. Could you get rid of that and calculate the power through arithmetic instead? Even recursive or iterative arithmetic might be faster than converting to String to grab bits of the number.
In a performance heavy application, you want to find a way to store basic information in primitives. In this case, perhaps you can split the bytes of a long or other variable in so that a fixed portion is the base.
Then, you can create custom methods the multiply long or Long as if they were a double. You grab the bits representing the base and exp, and truncate accordingly.
In some sense, you're re-inventing the wheel here, since you want byte code that efficiently performs the operation you're looking for.
edit:
If you want to stick with two variables, you can modify your code to simply take an array, which will be much lighter than objects. Additionally, you need to remove calls to any string parsing functions. Those are extremely slow.

Horner's recursive algorithm for fractional part - Java

I am trying to create a recursive method that uses Horner's algorithm to convert a fractional number in base n to base 10. I've searched here and all over but couldn't find anywhere that dealt with the fractional part in detail. As a heads up, I'm pretty weak in recursion as I have not formally learned it in my programming classes yet, but have been assigned it by another class.
I was able to make a method that handles the integer part of the number, just not the fractional part.
I feel like the method I've written is fairly close as it gets me to double the answer for my test figures (maybe because I'm testing base 2).
The first param passed is an int array filled with the coefficients. I'm not too concerned with the order of the coefficients as I'm making all the coefficients the same to test it out.
The second param is the base. The third param is initialized to the number of coefficients minus 1 which I also used for the integer part method. I tried using the number of coefficients, but that steps out of the array.
I tried dividing by the base one more time as that would give me the right answer, but it doesn't work if I do so in the base case return statement or at the end of the final return statement.
So, when I try to convert 0.1111 base 2 to base 10, my method returns 1.875 (double the correct answer of 0.9375).
Any hints would be appreciated!
//TL;DR
coef[0] = 1; coef[1] = 1; coef[2] = 1; coef[3] = 1;
base = 2; it = 3;
//results in 1.875 instead of the correct 0.9375
public static double fracHorner(int[] coef, int base, int it) {
if (it == 0) {
return coef[it];
}
return ((float)1/base * fracHorner(coef, base, it-1)) + coef[it];
}
Observe that fracHorner always returns a value at least equal to coef[it] because it either returns coef[it] or something positive added to coef[it]. Since coef[it] >= 1 in your tests, it will always return a number greater than or equal to one.
It's relatively easy to fix: divide both coef[it] by base:
public static double fracHorner(int[] coef, int base, int it) {
if (it == 0) {
return ((double)coef[it])/base;
}
return (fracHorner(coef, base, it-1) + coef[it])/base;
}

Value change when converting a long to a double and back

given the following code:
long l = 1234567890123;
double d = (double) l;
is the following expression guaranteed to be true?
l == (long) d
I should think no, because as numbers get larger, the gaps between two doubles grow beyond 1 and therefore the conversion back yields a different long value. In case the conversion does not take the value that's greater than the long value, this might also happen earlier.
Is there a definitive answer to that?
Nope, absolutely not. There are plenty of long values which aren't exactly representable by double. In fact, that has to be the case, given that both types are represented in 64 bits, and there are obviously plenty of double values which aren't representable in long (e.g. 0.5)
Simple example (Java and then C#):
// Java
class Test {
public static void main(String[] args) {
long x = Long.MAX_VALUE - 1;
double d = x;
long y = (long) d;
System.out.println(x == y);
}
}
// C#
using System;
class Test
{
static void Main()
{
long x = long.MaxValue;
double d = x;
long y = (long) d;
Console.WriteLine(x == y);
}
}
I observed something really strange when doing this though... in C#, long.MaxValue "worked" in terms of printing False... whereas in Java, I had to use Long.MAX_VALUE - 1. My guess is that this is due to some inlining and 80-bit floating point operations in some cases... but it's still odd :)
You can test this as there are a finite number of long values.
for (long l = Long.MIN_VALUE; l<Long.MAX_VALUE; l++)
{
double d = (double) l;
if (l == (long)d)
{
System.out.println("long " + l + " fails test");
}
}
Doesn't take many iterations to prove that;
l = -9223372036854775805
d = -9.223372036854776E18
(long)d = -9223372036854775808
My code started with 0 and incremented by 100,000,000. The smallest number that failed the test was found to be 2,305,843,009,300,000,000 (19 digits). So, any positive long less than 2,305,843,009,200,000,000 is representable exactly by doubles. In particular, 18-digit longs are also representable exactly by doubles.
By the way, the reason I was interested in this question is that I wondered if I can use doubles to represent timestamps (in milliseconds). Since current timestamps are on the order of 13 digits (and it will take for them rather long time to get to 18 digits), I'll do that.

Categories

Resources