How to increment a string by .i in Java? - java

My goal is to add value pairs to a HashMap and if a value is already taken it will increment the previous value by .i. What I mean by this is it would start as 0.1 ... 0.9 then 0.10, 0.11, 0.12 and so on...
I have started:
for (int i=0; i < 50; i++){
Double test = Double.parseDouble( 0 + "." + i);
But I cannot find a suitable test to add a decimal place onto the double once it has reached .9 (0.9, 0.10) Everything that I've tried doesn't work reliably. I was wondering if anyone could help.

What I mean by this is it would start as 0.1...0.9 then 0.10, 0.11,0.12 and so on...
To print this pattern, there simplest solution is to print the value as it really a String operation rather than a mathematical one.
for (int i = 1; i <= 50; i++)
System.out.println("0." + i);
NOTE: For double the value 0.1 == 0.10 and there is no way to tell them apart.

You can use DecimalFormat to get two decimal digits. The ".00" in the parameter tells the formatter to use two decimal places while the "#" means to display the whole number as it is
DecimalFormat df = new DecimalFormat("#.00");
for(int i=0;i < 50 ;i++){
Double test = Double.parseDouble( 0 + "." + i);
System.out.println(df.format(test));
Output:
.00
.10
.20
.30
.40
.50
.60
.70
.80
.90
.10
.11
.12
.13
.14
.15
.16
.17
.18
.19
.20

How about this
double division = 1.0;
for(int i=0;i < 50 ;i++){
if (i%10 == 0)
division *= 10;
Double test = i/division;
System.out.print(test + " ");
}
It will have duplicate each time it goes down one decimal, but I hope for testing it should be ok.

Related

Performing way to limit double accuracy

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

Retrieve numbers after comma (from double numbers)

Imagine that I have 4,81 (double), how can i get the figures after the comma?
I want to receive 8 as a Integer and 1 as another.
Thanks
Doubles are tricky to work with when you're interested in decimal properties such as the decimal digits of the fractional part.
I suggest you let String.valueOf do the transformation to decimal digits and work with the resulting string.
double d = 4.81;
String s = String.valueOf(d);
for (int i = s.indexOf(".") + 1; i < s.length(); i++) {
int digit = Character.getNumericValue(s.charAt(i));
System.out.println(digit);
}
Output:
8
1
You can always make this kind of loop:
double number = 4,81;
while (condition) {
number *= 10;
int nextNumber = Math.floor(number) % 10;
}

sum(1/prime[i]^2) >= 1?

While trying to devise an algorithm, I stumbled upon this question. It's not homework.
Let P_i = an array of the first i primes. Now I need the smallest i such that
Sum<n=0..i> 1 / (P_i[n]*P_i[n]) >= 1.
(if such i exists).
An approximation for the i'th prime is i*log(i). So I tried this in Java:
public static viod main(String args[]) {
double sum = 0.0;
long i = 2;
while(sum<1.0) {
sum += 1.0 / (i*Math.log(i)*i*Math.log(i));
i++;
}
System.out.println(i+": "+sum);
}
However the above doesn't finish because it converges to 0.7. However 1/100000000^2 rounds to 0.0 in Java, so that's why it doesn't work. For the same reason it doesn't even work if you replace the 6th line with
sum += 1.0 / (i*i)
while that should reach 1 if I'm not mistaken, because the sum should incease faster than 1/2^i and the latter converges to 1. In other words, this shows that Java rounding causes the sum to not reach 1. I think that the minimum i of my problem should exist.
On the maths side of this question, not the java side:
If I understand the problem, there is no solution (no value of i).
For any finite set P_i of primes {p_1, p_2,...p_i} let N_i be the set of all integers up to p_i, {1,2,3,...,p_i}. The sum 1/p^2 (for all p_n in P_i) will be less than the sum of all 1/x^2 for x in N_i.
The sum of 1/x^2 tends to ~1.65 but since 1 will never be in the set of primes, the sum is limited by ~0.65
You cannot use double for this, because it is not uniform. You should use fractions. I found this class https://github.com/kiprobinson/BigFraction
Then I tried to find whats happening :
public static void main(String args[]) {
BigFraction fraction = BigFraction.valueOf(1, 4);
int n = 10000000, status = 1, num = 3;
double limit = 0.4;
for (int count = 2; count <= n;) {
for (int j = 2; j <= Math.sqrt(num); j++) {
if (num % j == 0) {
status = 0;
break;
}
}
if (status != 0) {
fraction = fraction.add(BigFraction.valueOf(1,BigInteger.valueOf(num).multiply(BigInteger.valueOf(num))));
if (fraction.doubleValue() >= limit){
System.out.println("reached " + limit + " with " + count + " firsts prime numbers");
limit += 0.01;
}
count++;
}
status = 1;
num++;
}
}
This is having this output :
reached 0.4 with 3 firsts prime numbers
reached 0.41000000000000003 with 4 firsts prime numbers
reached 0.42000000000000004 with 5 firsts prime numbers
reached 0.43000000000000005 with 6 firsts prime numbers
reached 0.44000000000000006 with 8 firsts prime numbers
reached 0.45000000000000007 with 22 firsts prime numbers
And nothing more in a minute. I debug it and found that it grows extremely slower and slower, I do not think, it can reach 1 even in infinity :) (but dont know how to prove it).
I guess you might loose the precision you need when you use default Math.log multiplied by float i. I think this can be handled by using an appropriate RoundingMode. Please see setRoundingMode

Print on last iteration of for loop

So I have a simple for loop:
double bg = 5.0;
double f = 0.0;
for(double i = 0; i <= bg; i += 1)
{
f = f + ((2 * i + 1)*0.1);
if(i == bg)
{
System.out.printf ("%.1f" , f);
}
}
When I increment i with 1 for each itiration it works fine.
But when i do i += 0.1 it doesn't print f.
Any ideas why?
You can not compare floats like that.
Usually equality of two floats(doubles) is checked with something like
if (Math.abs(i - bg) < 0.00001f) //0.00001f is very small value - almost zero, pick this value to suit your needs
For more look at http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
Your code should look like
double bg = 5.0;
double f = 0.0;
for(double i = 0; i <= bg; i += 1)
{
f = f + ((2 * i + 1)*0.1);
if (Math.abs(i - bg) < 0.00001f)
{
System.out.printf ("%.1f" , f);
}
}
Floating-point numbers don't have exact representations for all the numbers you think they might. For example, when dividing 1 by 3, you get 0.333... since you use decimal numeric system.
However, computers use binary, so even though 0.1 seems like an easy and exact number to write, in binary it looks more like 0.0001100011..., and so on to infinity. And, since computers don't have infinite memory, this number is rounded to the closest possible representation. That's why the exact comparison does not work.
There are a number of ways to deal with this problem. One option is to use the delta comparison that's already been mentioned. However, if you know that you'll only be dealing with numbers of up to digits after the decimal point, you can instead multiply everything by 100 use integer numbers instead. This is the advised way if you're doing monetary calculations, for example.
In my graphical tools I'll iterate over an integer value and calculate the floats on the fly:
int bg = 5;
double f = 0.0;
for(int i = 0; i <= bg; i += 1) {
f = f + ((2 * i + 1)*0.1);
if(i == bg)
{
System.out.printf ("%.1f" , f);
}
}

java for-loop problem

I am making a Java program to calculate Simpson's rule for integrals. Here is the code I have. Notice the second column of numbers in the output values of count == 4,9,10,11. They are not numbers that I need, they do not follow the pattern. I need these numbers to be accurate. What is going on and how can I fix it?
public static void main(String[] args)
{
double totalS = 0.0;
int count = 0;
for(double i=0; i< 4; i += 0.4 )
{
count++;
totalS += Sfunction(i, count);
System.out.println(count + " " + i + " " + totalS);
}
}
public static double Sfunction(double f1, int count)
{
double value;
if (f1 == 0.0 || f1 == 4.0)
value = Math.cos(Math.sqrt(f1));
else if ((count % 2) == 1)
value = 2 * Math.cos(Math.sqrt(f1));
else
value = 4 * Math.cos(Math.sqrt(f1));
return value;
}
I get the output of:
1 0.0 1.0
2 0.4 4.226313639540303
3 0.8 5.478244888601832
4 1.2000000000000002 7.30884788480188
5 1.6 7.911122809972827
6 2.0 8.534897589034324
7 2.4 8.578100205110182
8 2.8 8.168723348285942
9 3.1999999999999997 7.736055200662704
10 3.5999999999999996 6.452869366954546
11 3.9999999999999996 5.620575693860261
Each time you go round your loop, you are compounding the error in the inexact addition of 0.4 to i.
Instead, use an integral value for the loop counter, and scale that to get a better approximation to the values:
for ( int count = 0; count < 10; ++count ) {
final double i = 0.4 * count;
System.out.println ( ( count + 1 ) + " " + i );
}
This will not eliminate the floating point error, but it will mean it is not increasing at each iteration. To remove the error from the output, format the output to a reasonable number of decimal places:
for ( int count = 0; count < 10; ++count ) {
final double i = 0.4 * count;
System.out.printf ( "%2d %.1f\n", ( count + 1 ), i );
}
This is a classic floating point problem. If you need accuracy in your decimals, you should be using BigDecimal
This is how floating point numbers work in computers.
You can round the display, but the representation underneath won't change. Use java.text.DecimalNumberFormat to round to two decimal places.
What you are seeing is a result of floating point precision error, the numbers aren't stored like you're probably thinking. You can round the answer to 1 decimal place to get rid of the error...but this is just a result of how doubles are stored in java.
There's some good reading on this topic over here: Why do simple math operations on floating point return unexpected (inaccurate) results in VB.Net and Python?
Your problem is that you are using floating point arithmetic which can only approximate values, but assuming you have infinite precision. You shouldn't do equality tests like this with floating point numbers:
if (f1 == 0.0 || f1 == 4.0)
Any equality test with a floating point number is a code smell. With a float you should always check if it lies within a certain range, for example in the range 3.9999 to 4.0001.
In this specific example though, you also handily have another parameter called count which is an int. You can do equality tests with that. Maybe you can test that instead.
try to print them with only one decimal digit:
System.out.printf("%.1f", Math.E); // prints 2.7
System.out.printf("%.2f", Math.E); // prints 2.72
System.out.printf("%.3f", Math.E); // prints 2.718
or even try to specify the keyword strictfp for your number crunching methods
From your loop condition, it looks like you don't want line 11 to be processed at all. I recommend you use an integer loop index and use it to compute the values you pass to Sfunction. The following should be the equivalent of what you have now (except it leaves out line 11).
double totalS = 0.0;
for( int i = 1; i <= 10; i++ )
{
double f1 = 0.4 * (i - 1);
totalS += Sfunction(f1, i);
System.out.println(i + " " + f1 + " " + totalS);
}
Your problem with print precision can be solved with DecimalFormat, as suggested in other answers.

Categories