I am trying to create an application that will return the three last digits before the decimal point of a double number.
In the below example, the outcome should be 006.
double number = 6.578336356630531E15;
int num = (int) number % 1000;
String output = String.format("%03d", num);
System.out.println(output);
But the result is : 647
But for the following with the same approach the outcome is correct:
Should return 006.
double number = 6.57833;
int num = (int) number % 1000;
String output = String.format("%03d", num);
System.out.println(output);
Result now is correct: 006
So I guess that the problem has to do with the very big number in the first example? But I need to deal with such big numbers.
Any explanation why this happened?
Cheers.
In the below example, the outcome should be 006
No. It should be 531, the last three digits of the value 6578336356630531.
But 6578336356630531 is alnmost certainly too large to fit into a double without loss of precision. A double only has 53 bits of precision, which is 15.9 decimal digits.
And casting that value to int is going to cause further truncation and loss of precision.
Try using long, as your conversion INT takes precedence on the modulo and you are loosing precision:
public static void main(String[] args) {
double number = 6.57833;
int num = (int) number % 1000;
String output = String.format("%03d", num);
System.out.println(output);
number = 6.578336356630531E15;
long num2 = (long) number % 1000;
output = String.format("%03d", num2);
System.out.println(output);
}
Worked for me. Gave me 531, which is the last 3 digits. Cheers!
Related
I need to put the decimal separator point in a Long, I have tried in several ways, but I need it to be dynamic since the decimal separator can change, I have tried with DecimalFormat format = new DecimalFormat("###.##"); but this is not dynamic and it doesn't work the way I wanted it to
Example 1
long amount = 123456;
int decimal = 2;
The result should be Double newAmount = 1234.56
Example 2
long amount = 123456;
int decimal = 4;
The result should be Double newAmount = 12.3456
If I understand correctly, this is what you are trying to achieve:
Long amount = 123456;
int decimal = 2;
double newAmount = amount.doubleValue();
newAmount = newAmount / Math.pow(10, decimal);
Use the pow method of java.lang.math to calculate the power of a number.
Be careful to declare your variable as an object of type Long and not a primitive type if you want to use one of its functions.
As suggested, it is even simpler to just use a double variable instead of a long from the start:
double amount = 123456;
int decimal = 2;
amount = amount / Math.pow(10, decimal);
You can get the required number by dividing the given number by 10 ^ decimalPlaces e.g.
public class Main {
public static void main(String[] args) {
// Test
System.out.println(getNum(123456, 2));
System.out.println(getNum(123456, 4));
}
static double getNum(long val, int decimalPlaces) {
return val / Math.pow(10, decimalPlaces);
}
}
Output:
1234.56
12.3456
All the other answers suggest converting to double and then scaling by powers of 10 before displaying. This will result in some unexpected results because of a loss of precision in the scaling operation. For the complete, gory details on why, please read
What Every Computer Scientist Should Know About Floating-Point Arithmetic and
Is Floating Point Broken?
As to your problem, you should be doing the work using BigDecimal. Converting from long (or Long) to BigDecimal does not lose precision, and will always produce the expected results.
BigDecimal even has a method to do the scaling for you:
long amount = 123456;
int decimal = 2;
BigDecimal n = BigDecimal.valueOf(amount).scaleByPowerOfTen(-decimal);
Output:
1234.56
Edit: This has to do with how computers handle floating point operations, a fact that every programmer faces once in a lifetime. I didn't understand this correctly when I asked the question.
I know the simplest way to start dealing with this would be:
val floatNumber: Float = 123.456f
val decimalPart = floatNumber - floatNumber.toInt() //This would be 0.456 (I don't care about precision as this is not the main objective of my question)
Now in a real world with a pen and a piece of paper, if I want to "convert" the decimal part 0.456 to integer, I just need to multiply 0.456 * 1000, and I get the desired result, which is 456 (an integer number).
Many proposed solutions suggest splitting the number as string and extracting the decimal part this way, but I need the solution to be obtained mathematically, not using strings.
Given a number, with an unknown number of decimals (convert to string and counting chars after . or , is not acceptable), I need to "extract" it's decimal part as an integer using only math.
Read questions like this with no luck:
How to get the decimal part of a float?
How to extract fractional digits of double/BigDecimal
If someone knows a kotlin language solution, it would be great. I will post this question also on the math platform just in case.
How do I get whole and fractional parts from double in JSP/Java?
Update:
Is there a "mathematical" way to "calculate" how many decimals a number has? (It is obvious when you convert to string and count the chars, but I need to avoid using strings) It would be great cause calculating: decimal (0.456) * 10 * number of decimals(3) will produce the desired result.
Update 2
This is not my use-case, but I guess it will clarify the idea:
Suppose you want to calculate a constant(such as PI), and want to return an integer with at most 50 digits of the decimal part of the constant. The constant doesn't have to be necessarily infinite (can be for example 0.5, in which case "5" will be returned)
I would just multiply the fractional number by 10 (or move the decimal point to the right) until it has no fractional part left:
public static long fractionalDigitsLong(BigDecimal value) {
BigDecimal fractional = value.remainder(BigDecimal.ONE);
long digits;
do {
fractional = fractional.movePointRight(1); // or multiply(BigDecimal.TEN)
digits = fractional.longValue();
} while (fractional.compareTo(BigDecimal.valueOf(digits)) != 0);
return digits;
}
Note 1: using BigDecimal to avoid floating point precision problems
Note 2: using compareTo since equals also compares the scale ("0.0" not equals "0.00")
(sure the BigDecimal already knows the size of the fractional part, just the value returned by scale())
Complement:
If using BigDecimal the whole problem can be compressed to:
public static BigInteger fractionalDigits(BigDecimal value) {
return value.remainder(BigDecimal.ONE).stripTrailingZeros().unscaledValue();
}
stripping zeros can be suppressed if desired
I am not sure if it counts against you on this specific problem if you use some String converters with a method(). That is one way to get the proper answer. I know that you stated you couldn't use String, but would you be able to use Strings within a Custom made method? That could get you the answer that you need with precision. Here is the class that could help us convert the number:
class NumConvert{
String theNum;
public NumConvert(String theNum) {
this.theNum = theNum;
}
public int convert() {
String a = String.valueOf(theNum);
String[] b = a.split("\\.");
String b2 = b[1];
int zeros = b2.length();
String num = "1";
for(int x = 0; x < zeros; x++) {
num += "0";
}
float c = Float.parseFloat(theNum);
int multiply = Integer.parseInt(num);
float answer = c - (int)c;
int integerForm = (int)(answer * multiply);
return integerForm;
}
}
Then within your main class:
public class ChapterOneBasics {
public static void main(String[] args) throws java.io.IOException{
NumConvert n = new NumConvert("123.456");
NumConvert q = new NumConvert("123.45600128");
System.out.println(q.convert());
System.out.println(n.convert());
}
}
output:
45600128
456
Float or Double are imprecise, just an approximation - without precision. Hence 12.345 is somewhere between 12.3449... and 12.3450... .
This means that 12.340 cannot be distinghuished from 12.34. The "decimal part" would be 34 divided by 100.
Also 12.01 would have a "decimal part" 1 divided by 100, and too 12.1 would have 1 divided by 10.
So a complete algorith would be (using java):
int[] decimalsAndDivider(double x) {
int decimalPart = 0;
int divider = 1;
final double EPS = 0.001;
for (;;) {
double error = x - (int)x;
if (-EPS < error && error < EPS) {
break;
}
x *= 10;
decimalPart = 10 * decimalPart + ((int)(x + EPS) % 10);
divider *= 10;
}
return new int[] { decimalPart, divider };
}
I posted the below solution yesterday after testing it for a while, and later found that it does not always work due to problems regarding precision of floats, doubles and bigdecimals. My conclusion is that this problem is unsolvable if you want infinite precision:
So I re-post the code just for reference:
fun getDecimalCounter(d: Double): Int {
var temp = d
var tempInt = Math.floor(d)
var counter = 0
while ((temp - tempInt) > 0.0 ) {
temp *= 10
tempInt = Math.floor(temp)
counter++
}
return counter
}
fun main(args: Array <String> ) {
var d = 3.14159
if (d < 0) d = -d
val decimalCounter = getDecimalCounter(d)
val decimalPart = (d - Math.floor(d))
var decimalPartInt = Math.round(decimalPart * 10.0.pow(decimalCounter))
while (decimalPartInt % 10 == 0L) {
decimalPartInt /= 10
}
println(decimalPartInt)
}
I dropped floats because of lesser precision and used doubles.
The final rounding is also necessary due to precision.
I want manage numbers on a range from:
from 0,001 to 999,999
For representation reasons, I want to drop some of the accuracy keeping only the 3 most important digits of the number.
For the number 123,12 I expect the result 123.
For the number 12,123 I expect the result 12,1.
For the number 0,001 I expect the result 0,001.
The best solution I thought of is transforming the number into a String, and back again to double, this way:
number = number*1000;
String s = new String(number);
s = s.substr(0, 3) + "000";
number = Double.parseDouble(s);
number = number/1000;
This does the job but it looks both poorly performing and not elegant.
Any more clever alternative?
Thank you!
Here's a somewhat-convoluted answer that doesn't require the use of any conversion to String:
final int numDigits = 3;
double d = 12.123;
int counter;
for (counter = 0; counter < numDigits && d < Math.pow(10, numDigits - 1); counter++) {
d *= 10;
}
d = Math.floor(d);
d /= Math.pow(10, counter);
System.out.println(d);
Output: 12.1
Essentially it multiplies the double by 10 until it reaches the largest value under 1000 (your maximum value is 999.999), keeping track of how many times it has been multiplied. It then performs the floor function to get rid of any precision to the right of the decimal point. Finally, we divide the number by 10, counter times, which provides us with the first 3 significant figures.
Perhaps use this RegEx to make the code more concise?
^[,0]{0,6}(\d{3}|\d{2},\d|\d,\d{2})
My code is to print the decimal equivalent of a binary number entered by user.
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
System.out.print("Enter a binary integer: ");
int b=in.nextInt();
int digits=1;
int q=b;
//determine the number of digits
while(q/10>=1){
++digits;
q/=10;
}
System.out.println(digits);
int decimal=0;
int i=0;
//pick off the binary number's digits and calculate the decimal equivalent
while(i<=digits-1){
decimal+=b/Math.pow(10,i)%10*Math.pow(2,i);
i++;
}
System.out.println(decimal);
}
}
When I enter 1101, it outputs 13, which is the right answer. However, when I
test the number 11001, the decimal equivalent is supposed to be 25, but it outputs 26. I try
to fix it but can't find where the bug is. Can you guys help me out?
The problem is that Math.pow returns a floating-point number, and you're doing floating-point calculations where you think you're doing integer calculations. When i is 4, and you calculate
b/Math.pow(10,i)%10*Math.pow(2,i);
the calculation goes like this:
b = 11001
b / Math.pow(10,i) = b / 10000 = 1.1001 (not 1)
1.1001 % 10 = 1.1001
1.1001 * Math.pow(2,i) = 1.1001 * 16 = 17.6016 (not 16)
This is then cast to an (int) when you add it to decimal. It truncates the last value to 17, but it's too late.
Casting the Math.pow results to an (int) will make it work. But this isn't the right approach anyway. If you want to learn how to do it yourself instead of using parseInt, it's best to input the number as a String (see my earlier comment), and then you don't have to worry about picking off the bits as decimal digits or powers of 10 at all anyway. Even using your approach, instead of Math.pow it would be simpler to keep powerOf10 and powerOf2 integer variables that you modify with powerOf10 *= 10; powerOf2 *= 2; in each loop iteration.
Try using:
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
System.out.print("Enter a binary integer: ");
int b=in.nextInt();
int answer = Integer.parseInt(in.nextInt() + "", 2);
System.out.println("The number is " + answer + ".");
}
}
2 is for base 2.
I have a double variable test. I want to extract the all digits before decimal point and two digits after the decimal point store the output in integer variables dollar, cents. how can i do it? I dont want any rounding to happen.
example:
double test= 12.1234
Output
int dollar =12;
int cents =12;
double test =1235.0
output
int dollar=1235
int cents =0
For currency, especially when you don't want any rounding, you should use the BigDecimal class. Something like:
BigDecimal test = new BigDecimal("12.1234");
int dollar = test.intValue();
int cents = test.scaleByPowerOfTen(2).intValue() - dollar * 100;
You can do:
double test= 12.1234;
int dollar = (int) test;
int cents = (int) ((test-dollar) * 100);
How about:
dollar = test;
test -= dollar;
cents = test * 100;
Line 1 assigns the integer part of test (12) to the integer 'dollar.'
Line 2 removes the 12 dollars from the test value.
Line 3 assigns 100 times the fractional part of test to cents. Note that I don't round here. For that, you'd have to:
cents = (test + 0.005) * 100
How about something like this. Rather than printing the values, you can simply assign them as you see fit.
double d = 32.456;
System.out.println( (int)d );
System.out.println( d-(int)d);
String[] s = Double.toString(test).split(".");
String dol = s[0];
String cent = s[1].substring(0,1);
For double values greater than 10^13, there won't be ANY significant digits after the notional decimal point.
You should not be using double or float for representing financial quantities. Use int or long (appropriately scaled and with explicit checks for overflow) or BigDecimal.