How do I store astronomically huge numbers into variables? - java

I'm still new to Java, and one of the ideas I had to make things more interesting is trying to make an algorithm that would convert numbers into letters (1000 = 1k // 1.000.000 = 1M // 1E+15 = 1aa..it would be an optimizer for a mobile game) , but turn out even double type variables has a pretty small limit compared to the numbers I want to work with (i.e 9.48E+3048).
Any ideas on how to approach this issue?

import java.math.BigInteger;
...
BigInteger myint = new BigInteger("5");
myint = myint.add(new BigInteger("7")); // 12
BigIntegers are immutable (They can't change), so the process is simply to .add, .multiply, etc, to get new numbers, and then overwrite variables as shown above. They will hold arbitrarily large numbers. All other functionality can be found here.
You will want to avoid converting integer to string as it will be too slow for numbers that large. Make a custom method to convert the most significant binary digits into the strings you desire (1k, 1M, 1aa, etc).
An alternative is hold two doubles in a (mantissa, exp) format, just as double does internally. After every operation, move the mantissa's exponent into the exponent variable with exp = this.getExponent(), mantissa = this.getMantissa(). getExponent could return something like floor(log(mantissa)) + exp, and getMantissa could return mantissa / nextLowerPowerOfTen(mantissa). This will give you 10^(10^3048), with 15 digits accuracy in the mantissa and 15 digits accuracy in the exponent.

Related

I am trying to divide a 19 digit number by 100 (19 digit number/100) in java

I am trying to divide a 19 digit number by 100, i.e. 19 digit number/100, in java. It can be divisible using long data type but I'm not getting the full value as 17 digits and a decimal point followed by another 2 digits. Instead, I'm only getting 17 digits as it was a long data type so I need that digit like mathematical expression.
long cardValue = ("1234567891234567891");
long divide = (cardValue/100);
System.out.println(divide);
Output: 12345678912345678
I need output as 12345678912345678.91
longs are large integers, and when you divide one by another you use integer division, which omits everything right of the decimal point.
You could use a BigDecimal instead:
BigDecimal divide = new BigDecimal(String.valueOf(cardValue)).divide(new BigDecimal(100));
Firstly, you are doing integer division, and then expecting a decimal value. In Java, 1234 / 10 results in 123, and not 123.4. If you want a decimal result, make one of the values decimal, i.e., 1234.0 / 10 or 1234 / 10.0. This will yield 123.4
As of your problem, since the number is very large, using BigDecimal is a better idea (not BigInteger, as it will again perform integer division, while you want a decimal result). So, try
BigDecimal b = new BigDecimal("1234567891234567891");
BigDecimal res = b.divide(new BigDecimal("100"));
Or you can do a one-liner as
new BigDecimal("1234567891234567891").divide(new BigDecimal("100"))
In first, res = 12345678912345678.91, and the other will also result in the same.
Note : Although BigInteger and BigDecimal are all included in java.math package, but if it raises an error, import it by using
import java.math.BigDecimal;
Integer and long don't have decimal point.
Instead, use double.
double a = 123456789.00
double answer = (a/100.00)
Refer primitive data types in java.
If you want to get the string and want to dive, then use parseDouble() method to convert it to double. After this step perform division.
The divide variable is long type, that means no decimal fractions, just integer values. If you use double, you can obtain decimals, but that type don't have the precision you need in this case because it gives up to 15 significant numbers.
Your only solution is to use BigDecimal class. You can obtain whatever digit numbers you want. We used it for Banks and accounting applications, and is easy to understand how to work with it.
HTH

Java - How to reduce float number precision? [duplicate]

This question already has answers here:
Java float 123.129456 to 123.12 without rounding
(5 answers)
How to round a number to n decimal places in Java
(39 answers)
Closed 5 years ago.
Can I reduce the precision of a float number?
In all the searching I've been doing I saw only how to reduce the precision for printing the number. I do not need to print it.
I want, for example, to convert 13.2836 to 13.28. Without even rounding it.
Is it possible?
The suggested answer from the system is not what I am looking for. It also deals with printing the value and I want to have a float.
There isn't really a way to do it, with good reason. While john16384's answer alludes to this, his answer doesn't make the problem clear... so probably you'll try it, it won't do what you want, and perhaps you still won't know why...
The problem is that while we think in decimal and expect that the decimal point is controlled by a power-of-10 exponent, typical floating point implementations (including Java float) use a power-of-2 exponent. Why does it matter?
You know that to represent 1/3 in decimal you'd say 0.3(repeating) - so if you have a limited number of decimal digits, you can't really represent 1/3. When the exponent is 2 instead of 10, you can't really represent 1/5 either, or a lot of other numbers that you could represent exactly in decimal.
As it happens .28 is one of those numbers. So you could multiply by 100, pass the result to floor, and divide by 100, but when this gets converted back to a float, the resulting value will be a little different from .28 and so, if you then check its value, you'll still see more than 2 decimal places.
The solution would be to use something like BigDecimal that can exactly represent decimal values of a given precision.
The standard warnings about doing precision arithmetic with floats applies, but you can do this:
float f = 13.2836;
f = Math.floor(f * 100) / 100;
if you need to save memory in some part of your calculation, And your numbers are smaller than 2^15/100 (range short), you can do the following.
Part of this taken from this post https://stackoverflow.com/a/25201407/7256243.
float number = 1.2345667f;
number= (short)(100*number);
number=(float)(number/100);
You only need to rememeber that the short's are 100 times larger.
Most answers went straight to how do represent floats more accurately, which is strange because you're asking:
Can I reduce the precision of a float number
Which is the exact opposite. So I'll try to answer this.
However there are several way to "reduce precision":
Reduce precision to gain performance
Reduce memory footprint
Round / floor arbitrarily
Make the number more "fuzzy"
Reduce the number of digits after the coma
I'll tackle those separately.
Reduce precision to gain performance
Just to get it out of the way: simply because you're dropping precision off of your calculations on a float, doesn't mean it'll be any faster. Quite the contrary. This answer by #john16384:
f = Math.floor(f * 100) / 100;
Only adds up computation time. If you know the number of significant digits from the result is low, don't bother removing them, just carry that information with the number:
public class Number WithSignificantDigits {
private float value;
private int significantdigits;
(implement basic operations here, but don't floor/round anywhere)
}
If you're doing this because you're worried about performance: stop it now, just use the full precision. If not, read on.
Reduce memory footprint
To actually store a number with less precision, you need to move away from float.
One such representation is using an int with a fixed point convention (i.e. the last 2 digits are past the coma).
If you're trying to save on storage space, do this. If not, read on.
Round / floor arbitrarily
To keep using float, but drop its precision, several options exist:
#john16384 proposed:
`f = Math.floor(f * 100) / 100;`
Or even
f = ((int) (f*100)) / 100.;
If the answer is this, your question is a duplicate. If not, read on.
Make the number more "fuzzy"
Since you just want to lose precision, but haven't stated how much, you could do with bitwise shifts:
float v = 0;
int bits = Float.floatToIntBits(v);
bits = bits >> 7; // Precision lost here
float truncated = Float.intBitsToFloat(bits);
Use 7 bitshifts to reduce precision to nearest 1/128th (close enough to 1/100)
Use 10 bitshifts to reduce precision to nearest 1/1024th (close enough to 1/1000)
I haven't tested performance of those, but If your read this, you did not care.
If you want to lose precision, and you don't care about formatting (numbers may stil have a large number of digits after the coma, like 0,9765625 instead of 1), do this. If you care about formatting and want a limited number of digits after the coma, read on.
Reduce the number of digits after the coma
For this you can:
Follow #Mark Adelsberger's suggestion of BigDecimals, or
Store as a String (yuk)
Because floats or doubles won't let you do this in most cases.

Fastest way to generate a random double number in java

In a project in which I'm working for, I'm required to either generate n random double numbers (depending from what the input file says) or converting them to doubles if I have them from my input file. Those numbers should have only 2 decimals after the comma (ex.: 0.98).
I know that in Java 8, there are 2 ways of doing this:
Java 8 way: nthNumber = Double.parseDouble(new DecimalFormat("#.##").format(ThreadLocalRandom.current().nextDouble(0,1)).replace(",","."));
Old fashion way: nthNumber = Double.parseDouble(new DecimalFormat("#.##").format(new Random().nextDouble()).replace(",", "."));
Asymptotically speaking, which is the fastest? From my poor knowledge of A.D.S., I'd say it would be the same time (O(n)?) but I'm not 100% sure
Aside from these two ways, are there any other ways to generate random doubles between 0 and 1 which are faster, asymptotically speaking, than my proposals? (rather, are there methods that can do everything in O(n) or O(1) ?)
Thank you in advance to everyone who will spend a minute to answer to this question of mine
Both of your approaches use strings as an intermediate representation, this will be quite inefficient (memory allocation, string parsing, string formatting are all relatively slow operations. You probably also want to avoid allocating multiple instances of Random.
Given that you only want two decimal digits, why not create an integer in the range of 0..99 and divide it by 100.0?
Random random = new Random(); // Only one instance needed.
for (int n = 0; n < total; n++) {
double nthRandomNumber = random.nextInt(100) / 100.0;
}
Your code looks complicated.
Did you consider the following:
DecimalFormat decimalFormat = new DecimalFormat("0.00");
String twoDigitRandom = decimalFormat.format(Math.random());
Reference:
https://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#random()
Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
Edit: Added after the comment:
If you would like to control the number of digits and not to have a String as end result, then I would advise not to use Double, try BigDecimal instead:
MathContext m = new MathContext(3);
BigDecimal randomWithTwoDigits = new BigDecimal(Math.random(), m);

Using Java BigDecimal for a 15 precision digit (scale of 2)

I found a partial answer here, but I knew this already. So I decided to post a new question.
I am trying to convert a HTTP request parameter string to a 15 precision Java BigDecimal number (with scaling of 2). For example,
String x = request.getParameter("seqNo"); /* e.g. 12345678910111213141516.17181920 whatever */
// I want to convert x so that it has a precision of 15 and scale of 2 i.e. 111213141516.17.
I don't care about rounding. It's a form of reference number, so irrelevant of rounding. I know that scaling can be set by using overloaded setScale(int) method that will return a scaled(Truncated?) BigDecimal. But how to make sure that the precision is set properly?
How about using substring instead? It's not really a number anyway.
int pos = x.indexOf('.');
String y = x.substring(pos - 12, pos + 3);
If you are really crazy enough to try processing this as numbers (collissions and differences in rounding are going to break your neck sooner or later!), you could do this.
double v = Double.parseDouble(y); // REALLY REALLY REALLY NOT RECOMMENDED.
But this is a very very bad idea. Don't squeeze something into a number column that is not a number. Next week, you'll get numbers with two dots, and it will break in every possible way.
If you do not need to do mathematical computations, treating such a field as VARCHAR or TEXT is perfectly acceptable. Because that is what it is: a sequence of characters. Not a number.
In fact, I would strongly advise to store the whole number, as VARCHAR. It is a unique identifier, not a mathematical number to do computations with.

How to actually avoid floating point errors when you need to use float?

I am trying to affect the translation of a 3D model using some UI buttons to shift the position by 0.1 or -0.1.
My model position is a three dimensional float so simply adding 0.1f to one of the values causes obvious rounding errors. While I can use something like BigDecimal to retain precision, I still have to convert it from a float and back to a float at the end and it always results in silly numbers that are making my UI look like a mess.
I could just pretty the displayed values but the rounding errors will only get worse with more editing and they make my save files rather hard to read.
So how do I actually avoid these errors when I need to use a float?
The Kahan summation and pairwise summation algorithms help to reduce floating point errors. Here's some Java code for the Kahan algorithm.
I would use a Rational class. There are many out there - this one looks like it should work.
One significant cost will be when the Rational is rendered into a float and one when the denominator is reduced to the gcd. The one I posted keeps the numerator and denominator in fully reduced state at all times which should be quite efficient if you are always adding or subtracting 1/10.
This implementation holds the values normalised (i.e. with consistent sign) but unreduced.
You should choose your implementation to best fit your usage.
A simple solution is to either use fixed precision. i.e. an integer 10x or 100x what you want.
float f = 10;
f += 0.1f;
becomes
int i = 100;
i += 1; // use an many times as you like
// use i / 10.0 as required.
I wouldn't use float in any case as you get more rounding errors than double for next to no benefit (unless you have millions of float values) double gives you 8 more digits of precision and with sensible rounding would won't see those errors.
If you stick with floats:
The easiest way to avoid the error is using floats which are exact, but
near the desired value which is
round(2^n * value) * 1/2^n.
n is the number of bits, value the number to use (in your case 0.1)
In your case with increasing precision:
n = 4 => 0.125
n = 8 (byte) => 0.9765625
n = 16 (short)=> 0.100006103516....
The long number chains are artefacts of the binary conversion,
the real number has much less bits.
As the floats are exact, addition and subtraction will
not introduce offset errors, but will always be
predictable as long as the number of bits is
not longer than the float value holds.
If you fear that your display will be compromised by
using this solution (because they are odd floats), use
and store only integers (step increase -1/1).
The final value which is internally set is
x = value * step.
As the step increases or decreases by an amount of 1,
precision will be retained.

Categories