java for-loop problem - java

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.

Related

How to increment a string by .i in 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.

Problems Generating A Math.random Number, Either 0 or 1

I want a random number, either 0 or 1 and then that will be returned to main() as in my code below.
import java.util.Scanner;
public class Exercise8Lab7 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int numFlips = 0;
int heads = 0;
int tails = 0;
String answer;
System.out.print("Please Enter The Number Of Coin Tosses You Want: ");
numFlips = input.nextInt();
for(int x = 1;x <= numFlips; x++){
if(coinToss() == 1){
answer = "Tails";
tails++;
}
else{
answer = "Heads";
heads++;
}
System.out.print("\nCoin Toss " + x + ": " + answer);
}
System.out.println("\n\n====== Overall Results ======" +
"\nPercentage Of Heads: " + (heads/numFlips)*100 + "\nPercentage Of Tails: " + (tails/numFlips)*100);
}
public static int coinToss(){
double rAsFloat = 1 * (2 + Math.random( ) );
int r = (int)rAsFloat;
return r;
}
}
Many solutions had been suggested to use the util.Random option which I have done and works perfectly but I want to sort out why I can't get this to work. Obviously I want the number to be an int myself so I convert it to an int after the random number has been generated. But no matter what I add or multiply the Math.random() by, it will always all either be Heads or all either be Tails. Never mixed.
Try this) It will generate number 0 or 1
Math.round( Math.random() ) ;
You could use boolean values of 0 or 1 based on value of Math.random() as a double between 0.0 and 1.0 and make the random generator much simpler. And you can get rid completely of the coinToss() method.
if(Math.random() < 0.5) {
answer = "Tails";
tails++;
}
Remove the coin toss method and replace the first conditional with the code above.
Math.random(); by itself will return a value between 0.0 and less than 1.0. If the value is in the lower half, [0.0, 0.5), then it has the same probability of being in the upper half, [0.5, 1.0). Therefore you can set any value in the lower half as true and upper as false.
Wierd that no one is using a modulo division for the random number.
This is the simplest implementation you can get:
Random rand = new Random();
int randomValue = rand.nextInt() % 2;
Math.round(Math.random()) will return either 0.0 and 1.0. Since both these values are well within the limits of int range they can be casted to int.
public static int coinToss(){
return (int)Math.round(Math.random());
}
(int)(Math.random()*2) also works fine in this case
its not working because of the integer math you are using, the call to 2+ Math.Random is pretty much always giving you a answer between 0.0 and 1.0.
so assuming that you recieve 0.25 as your result your maths is as follows
double d = 1* (2 + 0.25); // (result = 2
Then you are checking to see if your result == 1 ( which it never will. )
A better result would be to declare java.util.Random as a class variable and call random.nextBoolean() and simply perform your heads/tails calculation on that.
If you were to continue to use Math.random() and lets say
return Math.random() < 0.5
Your results would be ever so slightly skewed due to the fact that Math.random() cannot return 1.0, due to the fact that the java API specification states:
"Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0."
Math.random() returns a random float in the range [0.0,1.0)--that means the result can be anything from 0 up to but not including 1.0.
Your code
double rAsFloat = 1 * (2 + Math.random( ) );
will take this number in the [0.0,1.0) range; adding 2 to it gives you a number in the [2.0,3.0) range; multiplying it by 1 does nothing useful; then, when you truncate it to an integer, the result is always 2.
To get integers from this kind of random function, you need to figure out how many different integers you could return, then multiply your random number by that. If you want a "0 or 1" answer, your range is 2 different integers, so multiply Math.random() by 2:
double rAsFloat = 2 * Math.random();
This gives you a random number in the range [0.0,2.0), which can then be 0 or 1 when you truncate to an integer with (int). If, instead, you wanted something that returns 1 or 2, for example, you'd just add 1 to it:
double rAsFloat = 1 + 2 * Math.random();
I think you've already figured out that the Random class gives you what you want a lot more easily. I've decided to explain all this anyway, because someday you might work on a legacy system in some old language where you really do need to work with a [0.0,1.0) random value. (OK, maybe that's not too likely any more, but who knows.)
The problem can be translated to boolean generation as follow :
public static byte get0Or1 {
Random random = new Random();
boolean res= random.nextBoolean();
if(res)return 1;
else return 0;
}
Here it the easiest way I found without using java.util.Random.
Blockquote
Scanner input = new Scanner (System.in);
System.out.println("Please enter 0 for heads or 1 for tails");
int integer = input.nextInt();
input.close();
int random = (int) (Math.random() + 0.5);
if (random == integer) {
System.out.println("correct");
}
else {
System.out.println("incorrect");
}
System.out.println(random);
This will take a random double from (0 to .99) and add .5 to make it (.5 to 1.49). It will also cast it to an int, which will make it (0 to 1). The last line is for testing.
for(int i=0;i<100;i++){
System.out.println(((int)(i*Math.random())%2));
}
use mod it will help you!
One more variant
rand.nextInt(2);
As it described in docs it will return random int value between 0 (inclusive) and the specified value (exclusive)

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

Recursive Function and Non-recursive Function Returning Different Results

I'm creating two functions that are supposed to emulate and return the result of f(i) = 1/1 + 1/2 + 1/3 ... 1/i. One function is recursive, and I'm testing that the recursive function functions correctly by implementing a non-recursive version of it. However, I've found that both functions are returning similar answers that are not exactly the same. Can somebody please explain why the functions are returning different values?
When I run the functions in the main method of the class to which they belong, I get the following output:
Recursive for 1000: 7.4854784
Non-Recursive for 1000: 7.4854717
Recursive for 1: 1.0
Non-Recursive for 1: 1.0
Recursive for 483: 6.758268
Non-Recursive for 483: 6.758267
Here's my code:
static float RecursiveFunction(int num){
//The num parameter represents the denominator that will be used
//The recursive function is continually called at lower increments of num
//If num is one, return 1 and do not call RecursiveFunction again
if (num == 1) {
return 1;
}
//Otherwise, return 1/num (in floating point decimal) and call RecursiveFunction with a parameter of num - 1
else {
return 1/(float)num + RecursiveFunction(num - 1);
}
}
//A Non-recursive version of RecursiveFunction that will be used to test RecursiveFunction
static float NonRecursiveFunction(int num) {
//The total variable adds up the fractions
float total = 0;
//While num is greater than zero, add 1/num to total and then subtract 1 from num
while (num > 0) {
total += 1/(float)num;
num -= 1;
}
return total;
}
It is due to rounding errors from using the float datatype which is a single-precision 32-bit IEEE 754 floating point. When the number requires a greater precision than the datatype can cope with it will be rounded - this will happen when you are adding multiple floats together.
If you convert your float datatypes to BigDecimal then you will get the same answer from both methods:
import java.math.BigDecimal;
import java.math.RoundingMode;
public class RoundingErrors {
private static final BigDecimal ONE = new BigDecimal( 1 );
static BigDecimal RecursiveFunction(int num){
//The num parameter represents the denominator that will be used
//The recursive function is continually called at lower increments of num
//If num is one, return 1 and do not call RecursiveFunction again
if (num == 1) {
return ONE;
}
//Otherwise, return 1/num (in floating point decimal) and call RecursiveFunction with a parameter of num - 1
else {
return ONE.divide( new BigDecimal( num ), 100, RoundingMode.CEILING ).add( RecursiveFunction(num - 1) );
}
}
//A Non-recursive version of RecursiveFunction that will be used to test RecursiveFunction
static BigDecimal NonRecursiveFunction(int num) {
//The total variable adds up the fractions
BigDecimal total = new BigDecimal( 0 );
//While num is greater than zero, add 1/num to total and then subtract 1 from num
while (num > 0) {
total = total.add( ONE.divide( new BigDecimal( num ), 100, RoundingMode.CEILING ) );
num -= 1;
}
return total;
}
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println( RecursiveFunction( 1000 ));
System.out.println( NonRecursiveFunction( 1000 ));
}
}
Output
7.4854708605503449126565182043339001765216791697088036657736267499576993491652024409599344374118451321
7.4854708605503449126565182043339001765216791697088036657736267499576993491652024409599344374118451321
The only reason I can think of is because of the order of adding them together. The non-recursive function does this:
1/1 + (1/2 + (1/3 + (1/4 + (1/5 + (1/6 + 1/7)))))
While the recursive function does this:
((((((1/1 + 1/2) + 1/3) + 1/4) + 1/5) + 1/6) + 1/7)
This means that the recursive function is less precise. Why? Because floats are more dense around 0. So the closer to zero (of course, up to a certain level), the more precise your numbers are. The recursive function start with 1.5 and then starts adding smaller and smaller numbers. So you are immediately "pretty far away" from 0 in comparison to the flat function. The flat function sums the tiny numbers together first with high accuracy before getting to the bigger numbers.
I wrote a test program, and it demonstrates this explanation: http://ideone.com/4Eqduh.
Output is:
Rec: 7.4854784
Flat0: 7.4854717
Flat1: 7.4854784
MT0 BigDecimal: 7.4854708605503449126
Comparing this with the result from MT0, you can indeed see that the Flat0 function (which sums the small numbers first) is the most accurate.
You may want to look at http://en.wikipedia.org/wiki/Harmonic_number, I'm not a mathematician so I only sort of understood it but it may provide a way for you to avoid recursion/looping all together.

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

Categories