Convert double to long such that it equals increments from zero - java

Does there exist, or can you create, a fast method A() which converts a double to a long such that:
A(0d) = 0L
A(Math.nextUp(0d)) = 1L
A(Math.nextUp(Math.nextUp(0d))) = 2L
A(Math.nextUp(Math.nextUp(Math.nextUp(0d)))) = 3L
...
A(Double.MAX_VALUE) = Long.MAX_VALUE
A(-Double.MAX_VALUE) = -Long.MAX_VALUE
EDIT:
Just found an adequate answer myself. First of all the above is not quite possible due to the existence of NaN and infinity for double. The fact that Long does not have these means that Long.MAX_VALUE is larger than the amount of double bit permutations that create actual numbers.
However, despite this my usecase is actually just that I want a conversion that maps double to long while being order-preserving. As long as I don't encounter NaN or infinity I guess I should be able to just reinterpret double to long.
Double.doubleToLongBits(value)

Math.nextUp() will increase the fractional part not the whole part. To get the desired output, you have to call a() for each Math.nextUp().
public class D2L {
public static Long a(double input) {
return Math.round(Math.ceil(input));
}
public static void main(String[] args) {
System.out.println(a(0d)); //0L
System.out.println(a(Math.nextUp(a(0d)))); //1L
System.out.println(a(Math.nextUp(a(Math.nextUp(a(0d)))))); //2L
System.out.println(a(Math.nextUp(a(Math.nextUp(a(Math.nextUp(a(0d)))))))); //3L
System.out.println(a(Double.MAX_VALUE) + " = " +Long.MAX_VALUE); //9223372036854775807 = 9223372036854775807
System.out.println(-a(Double.MAX_VALUE) + " = " + -Long.MAX_VALUE); //-9223372036854775807 = -9223372036854775807
}
}

Related

method is performing incorrect calculations on double argument

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.

My program is not working properly

I have the following code in Java but it overflows when it shouldn't. Why?
public classO {
public static void main(String[] args) {
int big = Integer.MAX_VALUE;
System.out.println("big = " + big);
long bigger = big + 2;
System.out.println("bigger = " + bigger);
}
}
I get this output:
big = 2147483647
bigger = -2147483647
Why does it overflow? I have defined bigger as a long. What is wrong?
big + 2 is an integer operation and leads to your overflow (first you add two integers and afterwards you cast it to a long but at the point of castig the overflow has already happend).
use the following code to create a Long operation by casting your int before the add operation:
long bigger = (long) big + 2L;
big+2 will overflow as big is max. value while (long) big not
long bigger = (long) big +2
will work for you as it will treat big as long instead of integer.So make a cast of float to it.

Fixing a method and parameter error

Okay, so I just started this homework lab and I'm having a little bit of trouble. I've searched for any solutions but they all seem way more complex than what I can comprehend. I'm looking for the dollars needed and change needed to buy something. I just came up with some numbers and when i run the file i get an error. Can anyone help me find how to complete the equations to get the sum value. Also dollarsNeeded needs to be int and not double. The changeNeeded can be double. Any help would be greatly appreciated.
java:30: error: possible loss of precision
findDollars = xboxOne + newGame;
^
required: int
found: double
1 error
public class MoneyNeeded
{
public static void main(String[] args)
{
double xboxOne, newGame, moneyNeeded;
xboxOne = 320.41;
newGame = 64.36;
moneyNeeded = findMoney(xboxOne, newGame);
System.out.println(moneyNeeded);
int dollarsNeeded;
dollarsNeeded = findDollars(xboxOne, newGame);
System.out.println(dollarsNeeded);
double changeNeeded;
changeNeeded = findChange(xboxOne, newGame);
System.out.println(changeNeeded);
}
public static double findMoney(double xboxOne, double newGame)
{
double findMoney;
findMoney = xboxOne + newGame;
return findMoney;
}
public static int findDollars(double xboxOne, double newGame)
{
int findDollars;
findDollars = xboxOne + newGame;
return findDollars;
}
public static double findChange(double findDollars, double findMoney)
{
double findChange;
findChange = findMoney % findDollars;
return findChange;
}
}
So you can do :
findDollars = xboxOne.intValue() + newGame.intValue();
or
findDollars = (int)(xboxOne + newGame);
You can't sum two doubles and put the result in an int, because the int cannot contain the decimal part, so you will .. well .. loose precision.
If you are ok with loosing the decimal part, you can explicitly drop it in away :
findDollars = (int)(xboxOne + newGame); // Simply truncate the decimal part away
But usually is not a good idea, cause 0.2 + 0.2 will return 0.
I think your having issues because you're using datatypes as parameter for your methods, when they should be used for arguments in the method. I' m not sure though, so make sure to double check this.

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.

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