Performing way to limit double accuracy - java

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})

Related

How can I multiply all the digits in an integer (between 000 & 1000 exclusive) without using control statements or loops?

I'm trying to write a program that can multiply all the digits of a number from 0 to 1000 exclusive using only math expressions in Java. My program works fine as long as the user types in a 3-digit number, but results in 0 if they type in anything less than 100.
I have tried getting the last digit of the input with '%10' and removing the last digit with '/10' but without a control statement to detect if the input has been reduced to zero, the program ends up multiplying by 0 when a 2-digit number has been reduced to zero, giving an incorrect result.
public class MultiplyDigits {
public static void main(String[] args){
java.util.Scanner input = new java.util.Scanner(System.in);
System.out.print("Enter a number between 0 and 1000: ");
int number = input.nextInt();
int product = 1;
product*=number%10;
number/=10;
product*=number%10;
number/=10;
product*=number%10;
System.out.println(product);
}
}
An input of 55 should result in 25, but my program does 5 x 5 x 0 = 0
An input of 999 results in 729, which is correct. 9 x 9 x 9 = 729
Some more clarification, this is a problem out of the 2nd chapter of a textbook for complete novices. The author has not covered selection statements, loops, writing our own methods or classes, or anything more advanced than elementary programming, so the implication is that this is doable without those. The book has covered invoking methods in classes built into Java, although the author has only mentioned methods in the Math and System classes. For example, Math.max(), Math.min(), Math.pow(), System.currentTimeMillis();
What about this variant. To find the first number, you can decrease, first of all, the entered number by 100 and add 1 to avoid 0 during multipication. And , as recomended NVioli, the second number should be the same updated to have a possibility to enter number lower then 10. Thus, the final variant is:
int number = input.nextInt();
int t1 = 1 + (number-100) / 100;
int t2 = (1 + (number-10) / 10) % 10; \\By NVioli
int t3 = number % 10;
int product = t1 * t2 * t3;
System.out.println(product);
The first part is to extract the essential code into a separate Java method. I'm calling it dprod, which is short for "digit product".
static int dprod(int x) {
int hun = x / 100 % 10;
int ten = x / 10 % 10;
int one = x / 1 % 10;
return hun * ten * one;
}
The above code is the naive version that only works for numbers >= 100.
To treat numbers less than 100 as expected, you need to replace the hun or ten with 1 if it is 0.
static int dprod(int x) {
int hun = x < 100 ? 1 : x / 100 % 10;
int ten = x < 10 ? 1 : x / 10 % 10;
int one = x / 1 % 10;
return hun * ten * one;
}
The ?: operator is called a conditional operator, therefore it is probably not allowed under your rules. There is a possible workaround by using the ?: operator without writing it explicitly, by using the Math.max function.
static int dprod(int x) {
int hun = Math.max(100, x) / 100 % 10;
int ten = Math.max(10, x) / 10 % 10;
int one = x / 1 % 10;
return hun * ten * one;
}
The Math.max function uses the ?: operator internally, therefore it might be forbidden, too. This is subject to discussion though, since it depends on the exact wording of the rules and their intention.
If Math.max is forbidden, it is possible to implement it entirely without branches or conditions, see this C++ question, which can be translated to Java by replacing int32 with int and by replacing inline with static.
The complete code, including automatic tests, is:
package de.roland_illig.so;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
public class DprodTest {
static int dprod(int x) {
int hun = Math.max(x, 100) / 100 % 10;
int ten = Math.max(x, 10) / 10 % 10;
int one = x / 1 % 10;
return hun * ten * one;
}
#Test
public void testDprod() {
assertThat(dprod(999)).isEqualTo(729);
assertThat(dprod(123)).isEqualTo(6);
assertThat(dprod(99)).isEqualTo(81);
assertThat(dprod(9)).isEqualTo(9);
}
}
You could just initialize the program with a length 1000 array, initialize it with the value of each number, and then your real problem simplifies to:
System.out.println(calculatedArray[number]);
Your initialization could even take advantage of the fact that a leading 0 doesn't matter according to your rules (55 and 155 are the same result.)
calculatedArray[55] = calculcate(155);
there are some ways which can help you but all of them has a simple loop or if:
You can use digits = Logarithm of your number(10 base) and then you have number of digits, then you can use a loop to calculate the result. your loop will be repeated digit times so no matter how many digits your number has, it will always work.
You can check if your number is less than 100 and then just add 100 to that, then calculate the result, because of 1 * digit1 * digit2 there will be no error.

Get a numer decimal part as Integer using only math

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.

Do-while loop factorial. ( factorial *= x will eventually give a negative number) [duplicate]

I am currently taking pre-calculus and thought that I would make a quick program that would give me the results of factorial 10. While testing it I noticed that I was getting incorrect results after the 5th iteration. However, the first 4 iterations are correct.
public class Factorial
{
public static void main(String[] args)
{
int x = 1;
int factorial;
for(int n = 10; n!=1; n--)
{
factorial = n*(n-1);
x = x * factorial;
System.out.printf("%d ", x);
}
}//end of class main
}//end of class factorial
That is an Integer Overflow issue. Use long or unsigned long instead of int. (And as #Dunes suggested, your best bet is really BigInteger when working with very large numbers, because it will never overflow, theoretically)
The basic idea is that signed int stores numbers between -2,147,483,648 to 2,147,483,647, which are stored as binary bits (all information in a computer are stored as 1's and 0's)
Positive numbers are stored with 0 in the most significant bit, and negative numbers are stored with 1 in the most significant bit. If your positive number gets too big in binary representation, digits will carry over to the signed bit and turn your positive number into the binary representation of a negative one.
Then when the factorial gets bigger than even what an unsigned int can store, it will "wrap around" and lose the carry-over from its most significant (signed) bit - that's why you are seeing the pattern of sometimes alternating positive and negative values in your output.
You're surpassing the capacity of the int type (2,147,483,647), so your result is wrapping back around to the minimum int value. Try using long instead.
Having said the that, the method you are currently employing will not result in the correct answer: actually, you are currently computing 10! ^ 2.
Why complicate things? You could easily do something like this:
long x = 1L;
for(int n = 1; n < 10; n++)
{
x *= n;
System.out.println(x);
}
1
2
6
24
120
720
5040
40320
362880
which shows successive factorials until 10! is reached.
Also, as others have mentioned, if you need values bigger than what long can support you should use BigInteger, which supports arbitrary precision.
Your formula for the factorial is incorrect. What you will have is this:
Step 1 : n*(n-1) = 10 * 9 = 90 => x = 1*90 = 90
Step 2 : n*(n-1) = 9 * 8 = 72 => x = 90*72 = 6480 or, it should be : 10 * 9 * 8 => 720
But the wrong results are coming from the fact that you reached the maximum value for the type int as pointed out by others
Your code should be
public class Factorial
{
public static void main(String[] args)
{
double factorial = 1;
for(int n = factorial; n>=1; n--)
{
factorial = factorial * n;
System.out.printf("%d ", factorial );
}
}
}
In addition to what the other answers mention about the overflow, your factorial algorithm is also incorrect. 10! should calculate 10*9*8*7*6*5*4*3*2*1, you are doing (10*9)*(9*8)*(8*7)*(7*6)*...
Try changing your loop to the following:
int x = 1;
for(int n = 10; n > 1 ; n--)
{
x = x * n;
System.out.printf("%d ", x);
}
You will eventually overflow if you try to calculate the factorial of higher numbers, but int is plenty large enough to calculate the factorial of 10.

Factorial loop results are incorrect after the 5th iteration

I am currently taking pre-calculus and thought that I would make a quick program that would give me the results of factorial 10. While testing it I noticed that I was getting incorrect results after the 5th iteration. However, the first 4 iterations are correct.
public class Factorial
{
public static void main(String[] args)
{
int x = 1;
int factorial;
for(int n = 10; n!=1; n--)
{
factorial = n*(n-1);
x = x * factorial;
System.out.printf("%d ", x);
}
}//end of class main
}//end of class factorial
That is an Integer Overflow issue. Use long or unsigned long instead of int. (And as #Dunes suggested, your best bet is really BigInteger when working with very large numbers, because it will never overflow, theoretically)
The basic idea is that signed int stores numbers between -2,147,483,648 to 2,147,483,647, which are stored as binary bits (all information in a computer are stored as 1's and 0's)
Positive numbers are stored with 0 in the most significant bit, and negative numbers are stored with 1 in the most significant bit. If your positive number gets too big in binary representation, digits will carry over to the signed bit and turn your positive number into the binary representation of a negative one.
Then when the factorial gets bigger than even what an unsigned int can store, it will "wrap around" and lose the carry-over from its most significant (signed) bit - that's why you are seeing the pattern of sometimes alternating positive and negative values in your output.
You're surpassing the capacity of the int type (2,147,483,647), so your result is wrapping back around to the minimum int value. Try using long instead.
Having said the that, the method you are currently employing will not result in the correct answer: actually, you are currently computing 10! ^ 2.
Why complicate things? You could easily do something like this:
long x = 1L;
for(int n = 1; n < 10; n++)
{
x *= n;
System.out.println(x);
}
1
2
6
24
120
720
5040
40320
362880
which shows successive factorials until 10! is reached.
Also, as others have mentioned, if you need values bigger than what long can support you should use BigInteger, which supports arbitrary precision.
Your formula for the factorial is incorrect. What you will have is this:
Step 1 : n*(n-1) = 10 * 9 = 90 => x = 1*90 = 90
Step 2 : n*(n-1) = 9 * 8 = 72 => x = 90*72 = 6480 or, it should be : 10 * 9 * 8 => 720
But the wrong results are coming from the fact that you reached the maximum value for the type int as pointed out by others
Your code should be
public class Factorial
{
public static void main(String[] args)
{
double factorial = 1;
for(int n = factorial; n>=1; n--)
{
factorial = factorial * n;
System.out.printf("%d ", factorial );
}
}
}
In addition to what the other answers mention about the overflow, your factorial algorithm is also incorrect. 10! should calculate 10*9*8*7*6*5*4*3*2*1, you are doing (10*9)*(9*8)*(8*7)*(7*6)*...
Try changing your loop to the following:
int x = 1;
for(int n = 10; n > 1 ; n--)
{
x = x * n;
System.out.printf("%d ", x);
}
You will eventually overflow if you try to calculate the factorial of higher numbers, but int is plenty large enough to calculate the factorial of 10.

How do I parse non-integer octals in Java?

This may not be possible, but I figured it can't hurt to ask.
I have a program that needs to convert non-integer decimals into octal notation. From what I can tell, Java can only handle integer octals automatically. I've cobbled together something of a kludge, which involves breaking down the number into powers of eight, something like this.
.abcd = x * (1/8) + y * (1/64) + z * (1/512) + ......
which would be displayed as "0.xyz", if that makes any sense. The problem is, this is resulting in a lot of rounding/truncation errors for long numbers. Is there a better way to do this?
(edit)
Here's the algorithm I've been using to process the digits to the right of the decimal point:
double floatPartNum = Double.parseDouble("0." + temps[1]);
if (floatPartNum > 0) {
int p = 1;
result = result + ".";
while (floatPartNum > 0 && p < 16) {
double scale = 1/(Math.pow(8, p));
int modT = (int)( floatPartNum / scale );
result = result + modT;
double modScale = (double)modT * scale;
floatPartNum -= modScale;
p++;
}
}
I know of no floating point or fixed point support for octal numbers in base Java. If you show your algorithm for extracting the octal digits from the decimal, maybe we could help reduce the error.
There are some methods in the Float and Double classes that allow you to get the bit-wise representation of the number; for example Double.doubleToLongBits(double).
You could then extract the mantissa and exponent parts from the double-as-bits, and convert them to your octal format with no loss of precision.
However, it might be simpler to just fix your current algorithm. I'd have thought that you should be able to implement your approach without loss of precision. (Have you considered the possibility that the precision has already been lost; i.e. in the processes / calculations that produced your numbers in the first place?)
Your p < 16 is artificially truncating your output. When I try your code on 1.0/3.0, I get 0.252525252525252, but there's actually enough precision in the double to add three more octal digits, yielding 0.252525252525252525, if you change that to p < 20. But if you're concerned about "long numbers", then you might find that double just isn't big enough for your needs.
By the way, your loop can be simplified significantly, to:
for(int p = 1; floatPartNum > 0 && p < 20; ++p)
{
floatPartNum *= 8.0;
result = result + (int)floatPartNum;
floatPartNum -= (int)floatPartNum;
}
(tested), which eliminates all the need for Math.pow and so on. (Math.pow works by performing logarithms and exponentiations; it's overkill, and potentially roundoff-prone, when you're just multiplying by eight.)
How about something more like this?:
String result = "";
double floatPartNum = temps[1];
if( floatPartNum > 0 )
{
int p = 1;
result = result + ".";
while( floatPartNum > 0 && p < 16 )
{
floatPartNum *= 8.0D;
int modT = (int)floatPartNum;
floatPartNum -= modT;
result = result + modT;
p++;
}
}
Much fewer operations to introduce errors. (I am sorry I can't test this code before posting it, I am not near my programming tools.)

Categories