Separate double number larger than 10 digits in Java - java

I have written a code that separate a double number into whole and fraction part, but it gives the correct answer for number upto 10 digits only (decimal part+fraction part), how do i separate double number larger than 10 digits?
double num, temp;
int j=1;
int whole,frac;
num= 122.007094;
temp= num;
whole=(int)num;
// FOR THE FRACTION PART
do{
j=j*10;
}while((temp*j)%10!=0);
j=j/10;
frac= (int)(num*j)-(whole*j);
System.out.println("Double number= "+num);
System.out.println("Whole part= "+whole+" fraction part= "+frac);

Perhaps you could use java.lang.Math.floor(double) for the integer part, and then subtract that from the original number to get the fractional part. (If that doesn't do what you want for negative numbers, then use Math.ceiling(double) for the integer part when the number is negative.)

Here is an attempt at what I think you want. I've left the results in String form both to preserve leading zeros in the fraction part, and to avoid overflow. If you want to do arithmetic, rather than display, I recommend converting the String results to BigInteger, which will not overflow.
import java.math.BigDecimal;
public class Test{
public static void main(String[] args){
double num1 = 122.007094;
double num2 = 1236758511.98746514;
testIt(num1);
testIt(num2);
testIt(1e7);
testIt(0.1);
testIt(0.12345678901234);
}
public static void testIt(double in) {
String[] result = doubleSplit(in);
System.out.println("num="+in+" whole="+result[0]+" fraction="+result[1]);
}
/**
* Split the decimal representation of a double at where the decimal point
* would be. The decimal representation is rounded as for Double.toString().
* #param in The double whose decimal representation is to be split.
* #return A two element String[]. The first element is the part
* before where the decimal point would be. The second element is the part
* after where the decimal point would be. Each String is non-empty, with
* "0" for the second element for whole numbers.
*/
public static String[] doubleSplit(double in) {
/* Use BigDecimal to take advantage of its toPlainString. The
* initial Double.toString uses its rounding to limit the
* number of digits in the result.
*/
BigDecimal bd = new BigDecimal(Double.toString(in));
String [] rawSplit = bd.toPlainString().split("\\.");
if(rawSplit.length > 1){
return rawSplit;
} else {
return new String[]{rawSplit[0], "0"};
}
}
}
The output:
num=122.007094 whole=122 fraction=007094
num=1.2367585119874651E9 whole=1236758511 fraction=9874651
num=1.0E7 whole=10000000 fraction=0
num=0.1 whole=0 fraction=1
num=0.12345678901234 whole=0 fraction=12345678901234

Related

Program to count number of digits in a double following decimal point in Java

Below is a program that is supposed to count the number of digits in a double value following the decimal point. On entering some double values, the program tends to start an infinite loop (possibly due to floating-point imprecision). I do not want to use any wrapper methods (including String class). Could someone possibly provide an explanation for the endless loop for certain inputs and provide a solution?
import java.util.*;
class Flt
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
System.out.print("Enter a double number: ");
double f = sc.nextDouble();
double tmp = f;
int len = 0;
while(tmp != (int) tmp)
{
tmp *= 10;
len++;
}
System.out.println(len);
}
}
The problem overflows in the conversion to int, so tmp != (int) tmp is never true.
Consider a user input of “3.1415”. 3.1415 is not representable in the double format, so it is converted to the nearest representable value, 3.141500000000000181188397618825547397136688232421875. First, this has so many decimal digits that, even if the multiplications by ten were performed with exact real-number arithmetic, they would not produce an integer result until the number reached 3141500000000000181188397618825547397136688232421875. However, that number cannot be converted to int without overflow, because it is too large to be represented in an int. The conversion yields the largest value representable in int, 2147483647. Then comparing the number 3141500000000000181188397618825547397136688232421875 to the result of the conversion, 2147483647, indicates they are unequal, and the loop continues.
In fact, the multiplications by ten are not performed with exact real-number arithmetic. In each multiplication, the result is rounded to the nearest value representable in double. So the first yields 31.415000000000002700062395888380706310272216796875, the next 314.15000000000003410605131648480892181396484375, and so on. The first integer result is 31415000000000004. Again, this is too large to represent in an int, so tmp != (int) tmp is evaluated as 31415000000000004 != 2147483647, which is of course true, so the loop continues.
The infinite loop can be resolved by eliminating the conversion to int. For example, the test expression can be replaced by tmp % 1 != 0 to loop as long as tmp has a remainder when divided by 1 (hence is not an integer). However, then an input of “3.1415” yields 16—it does not count the number of decimal places in either the user’s input or the double that results from scanning it but rather the number of iterations until the multiplications with rounding yield an integer.
Once the user’s input has been converted to a double, there is no way to properly count the number of decimal places in the user’s input because the original value is lost. If the user enters either “3.1415” or “ 3.141500000000000181188397618825547397136688232421875”, the resulting double will be 3.141500000000000181188397618825547397136688232421875, so it is not possible to tell what the original number was. To count the number of decimal places in the user’s input, reading it as a string, looking for the decimal point, and count the digit characters after it (excluding trailing zeros if desired).

Return double type without trialing zero

I am trying to return the double/float value but without the trailing zero added to it.
I've used NumberFormat, DecimalFormat but once I cast double or float to the result, it will add trailing zero(which is expected). I was wondering if there is a way to prevent this.
private Double format (double input) {
NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);
Double result = null;
BigDecimal bd = new BigDecimal(input);
if(bd.intValue() > 99){
//(don't want to add trailing zeros here)
return (double)bd.intValue();
}else{
nf.setMinimumFractionDigits(1);
nf.setMaximumFractionDigits(1);
result = Double.parseDouble(nf.format(bd.doubleValue()));
}
return result;
P.S. I am not trying to return String value here.
The "trailing zeros" is only about the string representation of a float or double number.
As the trailing zeros do not affect the value of a number, the data stored in the float or double remains the same. For example, "3.4" and "3.4000" are the same number, it's only two different representations of this number, like "3.4 e+00" is still another way to display that very same number.
You can Use stripTrailingZeros which inbuilt method in Java that returns a BigDecimal after remove trailing zero.
Double.valueOf(bd.stripTrailingZeros().toPlainString());
If you assign an int value to a double variable, it will always be represented with a trailing zero by default. You have two choices:
Format it into a string in whichever you want.
Convert it into a BigDecimal and then use BigDecimal#stripTrailingZeros to get a BigDecimal without the trailing zero.
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
double x = 5;
System.out.println(x);
BigDecimal y = BigDecimal.valueOf(x).stripTrailingZeros();
System.out.println(y);
}
}
Output:
5.0
5

Why is my formatting so strange?

I have a problem with my code's formatting. At the end, it's supposed to print out its results. I am using a printf statement, but it returns numbers that aren't as precise as I need them to be. For example, if one number should be 76.83200000000001, it returns as 76.83200. It is also adding unnecessary zeros at the end of numbers, and if a number should be 28.0, it turns into 28.000000. If possible, can we do this without a BigDecimal variable? Here's my code so far (NOTE: there are spaces in front of some strings, that's because the website I'm submitting to requires that for some reason):
import java.util.Scanner;
public class Population {
public static void main(String[] args) {
Scanner stdin = new Scanner(System.in);
double startingNumber, dailyIncrease, daysWillMultiply, temp, population;
System.out.print("Enter the starting number organisms: ");
startingNumber = stdin.nextDouble();
while(startingNumber < 2) {
System.out.print("Invalid. Must be at least 2. Re-enter: ");
startingNumber = stdin.nextDouble();
}
System.out.print("Enter the daily increase: ");
dailyIncrease = stdin.nextDouble();
while(dailyIncrease < 0) {
System.out.print("Invalid. Enter a non-negative number: ");
dailyIncrease = stdin.nextDouble();
}
System.out.print("Enter the number of days the organisms will multiply: ");
daysWillMultiply = stdin.nextDouble();
while(daysWillMultiply < 1) {
System.out.print("Invalid. Enter 1 or more: ");
daysWillMultiply = stdin.nextDouble();
}
temp = startingNumber * dailyIncrease;
population = startingNumber;
System.out.println("Day\t\tOrganisms");
System.out.println("-----------------------------");
System.out.println("1\t\t" + startingNumber);
for (int x = 2; x <= daysWillMultiply; x++) {
population += temp;
temp = population * dailyIncrease;
System.out.printf(x + "\t\t%f\n", population);
}
}
}
Well, I deleted my previous answer as it was absolutely wrong (thanks to #JohnKugelman for pointing this out). I thought that precision is lost due to converting to float, but it is not true.
According to the formatter documentation, here's what happens when %f flag is used:
The magnitude m (absolute value of the argument) is formatted as
the integer part of m, with no leading zeroes, followed by the
decimal separator followed by one or more decimal digits representing
the fractional part of m.
The number of digits in the result for the fractional part of m is equal to the precision. If the precision is not specified then
the default value is 6
If the precision is less than the number of digits which would appear
after the decimal point in the string returned by
Float.toString(float) or Double.toString(double) respectively,
then the value will be rounded using the round half up algorithm.
Otherwise, zeros may be appended to reach the precision.
That's why you get unnecessary zeros and cut digits.
The documentation suggests to use Float.toString(float) or Double.toString(double) for a canonical representation of the value.
If you want to use System.out.printf(...);, you can just replace your %f flag with %s - in this case the argument will be converted to a string (the result is obtained by invoking the argument's toString() method, and this is what you need). For example, you could rewrite this line:
System.out.printf(x + "\t\t%f\n", population);
as follows:
System.out.printf("%d\t\t%s\n", x, population);
This will print the exact value of your population.
Check first answer of this thread, it maybe helpful.
How many significant digits have floats and doubles in java?
It's important to understand that the precision isn't uniform and that
this isn't an exact storage of the numbers as is done for integers.

Java DecimalFormat losing precision while formatting double

When i execute the below code:
public class Test {
public static void main(String args[]){
DecimalFormat format = new DecimalFormat();
Double value = new Double(-1350825904190559999913623552.00);
StringBuffer buffer = new StringBuffer();
FieldPosition position = new FieldPosition(0);
format.format(new BigDecimal(value), buffer, position);
System.out.println(buffer);
}
}
This correctly prints -1,350,825,904,190,559,999,913,623,552.
I have code which does go through a lot of doubles so I dont want the conversion from double to bigdecimal. I figured the processing time for BigDecimal is large.
So i do format.format(value, buffer, position)
And i see the precision is lost.
The output I get is -1,350,825,904,190,560,000,000,000,000.
What am i doing wrong here? Is there a better way to deal with this and still retain the precision. I don't want to deal with BigDecimals here but just work with the decimals.
Any suggestions?
double doesn't have infinite precision, and you can't gain more precision than a double has by converting a double to a BigDecimal (like you can't gain more precision with an int when you do double r = 1/3; which is 0.0 because it widens an int to a double). Instead, you could use a String. Something like
DecimalFormat format = new DecimalFormat();
String value = "-1350825904190559999913623552.00";
System.out.println(format.format(new BigDecimal(value)));
It isn't lost during formatting. It is lost right here:
Double value = new Double(-1350825904190559999913623552.00);
A double only has about 15.9 significant decimal digits. It doesn't fit. There was a precision loss at compile time when the floating-point literal was converted.
The issue is in the output formatting, specifically how doubles are converted to strings by default. Each double number has an exact value, but it is also the result of string to double conversion for a range of decimal fractions. In this case, the exact value of the double is -1350825904190559999913623552, but the range is [-1350825904190560137352577024,-1350825904190559862474670080].
The Double toString conversion picks the number from that range with the fewest significant digits, -1.35082590419056E27. That string does convert back to the original value.
If you really want to see the exact value, not just enough digits to uniquely identify the double, your current BigDecimal approach works well.
Here is the program I used to calculate the numbers in this answer:
import java.math.BigDecimal;
public class Test {
public static void main(String args[]) {
double value = -1350825904190559999913623552.00;
/* Get an exact printout of the double by conversion to BigDecimal
* followed by BigDecimal output. Both those operations are exact.
*/
BigDecimal bdValue = new BigDecimal(value);
System.out.println("Exact value: " + bdValue);
/* Determine whether the range is open or closed. The half way
* points round to even, so they are included in the range for a number
* with an even significand, but not for one with an odd significand.
*/
boolean isEven = (Double.doubleToLongBits(value) & 1) == 0;
/* Find the lower bound of the range, by taking the mean, in
* BigDecimal arithmetic for exactness, of the value and the next
* exactly representable value in the negative infinity direction.
*/
BigDecimal nextDown = new BigDecimal(Math.nextAfter(value,
Double.NEGATIVE_INFINITY));
BigDecimal lowerBound = bdValue.add(nextDown).divide(BigDecimal.valueOf(2));
/* Similarly, find the upper bound of the range by going in the
* positive infinity direction.
*/
BigDecimal nextUp = new BigDecimal(Math.nextAfter(value,
Double.POSITIVE_INFINITY));
BigDecimal upperBound = bdValue.add(nextUp).divide(BigDecimal.valueOf(2));
/* Output the range, with [] if closed, () if open.*/
System.out.println("Range: " + (isEven ? "[" : "(") + lowerBound + ","
+ upperBound + (isEven ? "]" : ")"));
/* Output the result of applying Double's toString to the value.*/
String valueString = Double.toString(value);
System.out.println("toString result: " + valueString);
/* And use BigDecimal as above to print the exact value of the result
* of converting the toString result back again.
*/
System.out.println("exact value of toString result as double: "
+ new BigDecimal(Double.parseDouble(valueString)));
}
}
Output:
Exact value: -1350825904190559999913623552
Range: [-1350825904190560137352577024,-1350825904190559862474670080]
toString result: -1.35082590419056E27
exact value of toString result as double: -1350825904190559999913623552
You cannot represent 1350825904190559999913623552.00 accurately with a Double. If you would like to know why, explore this article.
Should you want to represent the value, I would advise using the code you have used in your question: new BigDecimal( value ), where value is actually a String representation.

Only return a decimal if it's not a whole number. JAVA

I've been trying to write a function isWhole that is given a double and looks to see if it's a whole number if it is return the value without the decimal(as an int?) else return it with 3 decimal places(I can do this part with number format.
My question is how can I check if a double is a whole number and even a recursive decimal?
[UPDATE] returns value - with 3 decimal places
public boolean isWhole(double value) {
return Math.floor(value) == value;
}
You can't have a function that returns either int or double
To convert double to int; simply typecast :- int valueInt = (int) valueDouble;
My first advice would be: keep it simple. Java has functions that make this sort of thing easy:
import java.Math;
public class MyFunctionsLibrary {
public static boolean isWhole(double x) {
if(x - Math.floor(x) == 0)
return true;
else
return false;
}
public static void testIt() {
double a = 123.456;
Integer whole = null;
Double nonWhole = null;
if(isWhole(a))
whole = new Integer(Math.floor(a));
else
nonWhole = new Double(a);
}
}
if(Math.abs(in-Math.floor(in)) < 0.001){
/* is whole number */
} else {
/* is not whole number */
}
Whole number isn't really defined for doubles, so a whole number can be seen as a number that has would not result in n.000. 0.001 is chosen specifically because it is the intended output precision.
This was my original answer:
How about
Math.floor(x)==x
The floor leaves the x unchanged, bit-by-bit if it is a mathematical integer (say the docs), so the equality should hold exactly when there is nothing to round.
After some thought, I think using exact comparison may lead to unwanted results. The question is, what the requirements of the OP really are. Is it
If it is a mathematical integer, show the number with no digits
after the decimal point, if it is not, show 3 digits after the
decimal point. Or is it
If formatting with three digits results in 000 after the decimal point, show only an integer.
The solution shown above and in other answers only works, if (1) is the requirement, because the number 2.000001 would turn out as 2.000, because it is not a mathematical integer.
If the Locale is fixed to a default, formatting 1.0 for the endsWith()-pattern can of course be optimized into a fixed string like ".000" or ",000".
If (2) is actually requested, my hunch is that there is no way around first formatting the number to a string and only then stripping the zeros, like so:
String format(Locale l, double d) {
String zeros = String.format(l, "%.3f", 1.0d);
String s = String.format(l, "%.3f", d);
if (s.endsWith(zeros.substring(1))) {
return s.substring(0, s.length()-4);
}
return s;
}
To see if a double is a whole number use
double d;
int whole = (int) d;
if(whole == d){
return whole;
}
else{
(your formatting here)
return formattedDouble;
}
You could check if it is recursive by creating:
String s = d + "";
for(int i = 1; i < s.length(); i++){
if(s.charAt(i) == s.charAt(i-1)){
continue;
}
else{
return false;
}
}

Categories