Loss of accuracy with floats - java

I am trying to compute a summation of float numbers. All small numbers output properly, when I use very large numbers as inputs, the output is always off by a few integers. For example, H = 5764801 W = 1679616, on paper, works out as 335923 30275911. In my program though, 335923 30275908 is printed instead. Here is the code:
public void printOutput(int H, int W) // The inputs
{
if(H == 1 && W == 1)
{
System.out.println(0 + " " + 1);
return;
}
List<Integer> pfw = primeFactors(W);
int y = 1;
while(H != (int) (Math.pow(Math.pow(W, 1f/y) + 1f, y))) y++;
final float N = findWholeNumber(pfw);
float height = 0;
for(int x = 1; x <= y + 1; x++)
{
height += (float) (W * Math.pow((N + 1f) / N, x-1f) + 1e-8); //Here is the summation
}
float cats = 1;
for(int x = 2; x <= y + 1; x++)
cats += (float) (Math.pow(N, x-1));
int notWorking = (int) (cats - W);
System.out.println(notWorking + " " + (int)height); //Outputs printing
}
private int findWholeNumber(List<Integer> factors)
{
List<Integer> common = new ArrayList<Integer>();
for(int i = 0; i < factors.size(); i++)
{
if(common.contains(factors.get(i))) continue;
common.add(factors.get(i));
}
int num = common.get(0);
for(int i = 1; i < common.size(); i++)
num *= common.get(i);
return num;
}
private List<Integer> primeFactors(int num)
{
List<Integer> pf = new ArrayList<Integer>();
if(num == 1)
{
pf.add(1);
return pf;
}
for(int j = 2; j <= num; j++)
while(num % j == 0) // is prime
{
pf.add(j);
num /= j;
}
return pf;
}
}

Floating point numbers have a limited precision as mantissa has a limited width.
You could try double for your case which precision is more (as its mantissa is wider), but it is also limited.
More information: https://en.wikipedia.org/wiki/IEEE_floating_point#IEEE_754-2008 and What is the maximum number in the mantissa part of a Java float?
If you need to have an unlimited precision, try BigDecimal. The count of significant digits there is only limited by the amount of your memory.
If you only need integer values, BigInteger is an option.

Study What Every Computer Scientist Should Know About Floating-Point Arithmetic, David Goldberg, 1991.
https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Related

Simpson's double integral won't work in java

So I had to write an algorithm for the Simpson's double integral so I can find the answer in a much faster manner. I had a guide that showed the steps to follow to write this program. After following this guide and running it in netbeans, I found out that the values coming out of the program where not really close to the real answer. This is the code that I written in java:
//INPUT
double a = 0,b = 1; // Endpoints
int m = 8,n = 4;
double K1 = 0, K2 = 0, K3 = 0;
//OUPUT
//Step 1
double h = (b - a) / n;
double j1 = 0; //End terms
double j2 = 0; //Even terms
double j3 = 0; //Odd terms
//Step 2
for(int i = 0; i <= n; i++){
//Step 3
double x = a + (i * h);
double hX = (d(x) - c(x)) / m;
K1 = f(x, c(x)) + f(x, d(x)); // End terms
//Step 4
for (int j = 1; j < (m-1); j++){
//Step 5
double y = c(x) + (j * hX);
double q = f(x,y);
//Step 6
if (j % 2 == 0){
K2 = K2 + q;
}
else
K3 = K3 + q;
}
//Step 7
double l = (K1 + (2*K2) + (4*K3)) * (hX / 3);
//Step 8
if (i == 0 || i == n)
j1 = j1 + l;
else if (i % 2 == 0)
j2 = j2 + l;
else
j3 = j3 + l;
}
double j = h * (j1 + (2 * j2) + (4 * j3)) / 3;
System.out.println("j = " + j);
}
public static double c(double x){
return x;
}
public static double d(double x){
return 2 * x;
}
public static double f(double x, double y){
return (Math.pow(y, 2) + Math.pow(x, 3));
}
I tried debugging the program several times but I haven't yet found why I am encountering this mistake. If there's any mistake that you find in my code please let me know to see if it fixes it. For the given example, I am getting the value of 0.9069281684027777 instead of having the correct value which is 0.7838542. Thank you for your help. You can also see the guide that I followed to be able to create this program.
I did not check the math, the large error seems to indicate an error in the algorithm implemented. The for-bounds are dubious. And floating point errors exist.
Instead of multiplying a fraction by a running index (which would multiply the floating point approximation error in the fraction), better do:
Instead:
double h = (b - a) / n;
for (int i = 0; i <= n; i++) {
double x = a + (i * h);
do
for (int i = 0; i < n; i++) {
double x = a + i * (b - a) / n;
or
for (int i = 0; i <= n; i++) {
double x = a + i * (b - a) / (n + 1);
The boundary n being a bit unclear to me.

I expect the Histogram to be showed in the range of min and max of my image value ,But it includes bigger values than max-value

I use Conrad open source and I want to compute the histogram of an image. For that first, I found the min and max of my image values and range=max-min and then the lower-limit and upper-bound exactly according to this link https://www2.southeastern.edu/Academics/Faculty/dgurney/Math241/StatTopics/HistGen.htm
Now my problem is that how can the program divide the range according to the bin-Width and how can I assign each image values to each bin-width(classes).
public static int[] computeHistogram2D(Grid2D grid, int bins, int width, int heigth) {
float val = 0;
float max = -Float.MAX_VALUE;
float min = Float.MAX_VALUE;
for (int i = 0; i < width; i++) {
for (int j = 0 ; j < heigth; j++) {
val = grid.getAtIndex(i, j);
if (val > max) {
max = val;
}
if (val < min) {
min = val;
}
}
}
int[] histo = new int[bins];
double[] histof = new double[bins];
float range = max - min;
float lowerLimit = range/(float)bins;
float upperBound = range / (float) (bins -1);
//float binWidth =( upperBound - lowerLimit)/bins;
for (int i = 0; i < width; i++) {
for (int j = 0 ; j < heigth; j++) {
val = grid.getAtIndex(i, j);
int b = (int) ((val - min) / upperBound);
histo[b]++;
histof[b]++;
System.out.println(" intervals " + b );
}
}
System.out.println("maxValgrid2D: " +max + " minValGrid2D: " + min + " binWidth "+ upperBound);
VisualizationUtil.createPlot(histof, "Histogram2D", "intensity", "count").show();
return histo;
}
This is what I got as a result,which seems to be wrong because the max-value of my pic is 21.12
What I expect to get

How to split an integer into individual digits and then square each number?

I want to split an integer into digits and then raise each number to the power 2 and print that out. This is what I have:
int n = 666;
String number = String.valueOf(n);
for (int i = 0; i < number.length(); i++) {
int j = Character.digit(number.charAt(i), 10);
Math.pow(j, 2);
System.out.println(j);
}
The output is only the 666 number.
What is it I'm doing wrong?
Math.pow(j, 2) doesn't modify j, it returns a new value. You should capture the output of Math.pow to a variable and print that
If you want to print sq of individual digits.
int num = 666;
String number = String.valueOf(num);
for (int i = 0; i < number.length(); i++) {
int j = Character.digit(number.charAt(i), 10);
int res = (int) Math.pow((double) j, (double) 2);
System.out.println("digit: " + res);
}
int m = n;
while (m > 0)
{
int digit = m % 10;
System.out.printf("%d\n", Math.pow(digit, 2));
m /= 10;
}
Is this what you want?
Due to Andreas comment which said the order is reversed, I changed the code:
int length = number.length();
for (int i = length - 1; i >= 0; i--)
{
int divisor = (int) Math.pow(10, i);
int digit = n % divisor;
System.out.printf("%d\n", Math.pow(digit, 2));
}
Also I could have written it as:
int length = number.length();
int divisor = (int) Math.pow(10, length - 1);
while (divisor > 0)
{
int digit = n % divisor;
System.out.printf("%d\n", Math.pow(digit, 2));
divisor /= 10;
}
Your code isn't working because you don't actually use the return value of Math.pow().
Math.pow(x, 2) is one way to raise a number to the power of 2, but it is floating-point math, not integer math. Power of 2 means to multiply the number by itself, so x * x is much better.
int number = 299792458; // Speed of light in m/s
for (char ch : Integer.toString(number).toCharArray()) {
int digit = ch - '0';
System.out.println(digit * digit);
}
Or using Java 8 streams:
int number = 299792458; // Speed of light in m/s
Integer.toString(number)
.chars()
.map(c -> (c - '0') * (c - '0'))
.forEach(System.out::println);
OUTPUT
4
81
81
49
81
4
16
25
64

What's the difference when using numeric literal in termination expression of a for statement?

Why does this piece of code:
String value = JOptionPane.showInputDialog("Enter x"); //Input = 100
int x = Integer.parseInt(value);
double result = 1;
for (int i = 1; i <= x; i++) //used variable "x" here
{
result += (x * 1.0) / fact(i);
x *= x;
}
public static int fact(int n) {
int fact = 1;
for (int i = 1; i <= n; i++) {
fact *= i;
}
return fact;
}
work differently from this one?
String value = JOptionPane.showInputDialog("Enter x"); //Input = 100
int x = Integer.parseInt(value);
double result = 1;
for (int i = 1; i <= 100; i++) //and here I used the value "100"
{
result += (x * 1.0) / fact(i);
x *= x;
}
public static int fact(int n) {
int fact = 1;
for (int i = 1; i <= n; i++) {
fact *= i;
}
return fact;
}
The only change that I made was using the value 100 instead of using the variable x in my termination expression!
When I run the first code, I get:
9.479341033333334E7
However, for the second one I always get
NaN
Why?
The difference between the two snippets is this:
for (int i = 1; i <= x; i++) {
vs.
for (int i = 1; i <= 100; i++) {
In the first case, x gets much larger every time! Eventually, it will stop when x overflows and becomes 0, which will be much sooner than in the second case. For an explanation as to why this results in 0 instead of some other random number, see: Why does this multiplication integer overflow result in zero?
In the second case, when i = 34, fact(n) will return 0, so the double division is (0 * 1.0) /0 which results in NaN. Any double, when added to NaN, becomes NaN, which is why the second snippet results in NaN. See: In Java, what does NaN mean?

nested for() loops && using the "i" count from the first loop in the second so i loops just once using the value?

i am trying to not import the math class to use but i am still trying to estimate the constant "e". it is said e= 1+(1/1!)+(1/2!)+(1/3!)+(1/4!)+(1/5!)+.....
these are what i have int at the top
String userInput;
int uIp; // this converts the string into int type
double e = 2;
then i ask some questions then i check to see not zero to exit and non negative to continue
While(uIp >0){
final int endTheLoop = 15;
int factorialNumber = 1;
double e2TheUserInput=0;
for(int i = 2; i < endTheLoop; i++){
for(int j = 1; j < i; j++){
factorialNumber = ((i - 1) * factorialNumber);
}
e = (1/factorialNumber) + e;
e2TheUserInput = Math.pow(e,uIp);
}
}
You are doing integer division(but e is a double right?):
e = (1/factorialNumber) + e;
Correct that to:
e = (1.0/(double)factorialNumber) + e;
It was counting all the loops, but changes are zero according to the integer division. :)
e= 2+(0)+(0)+(0)+(0)+.....
I am not sure what your code is trying to do but if you want to compute exp(x) this is how I would do it.
public static void main(String... args) {
for (int i = -4; i <= 4; i++)
System.out.println(i + ": " + exp(i) + " cf " + Math.exp(i));
}
private static double exp(double d) {
if (d < 0)
return 1 / exp(-d);
double e = 1, term = 1;
for (int i = 1; i < 20 || term > e * 1e-16; i++) {
term *= d / i;
e += term;
}
return e;
}
For large exponents, it more efficient to evaluate the integral powers without using a taylor series.
public static final double E = 2.7182818284590452354;
private static double exp(double d) {
if (d < 0)
return 1 / exp(-d);
long num = (long) d;
double numE = 1;
double mult = E;
while (num > 0) {
if ((num & 1) != 0)
numE *= mult;
num >>>= 1;
mult *= mult;
}
double fract = d - (long) d;
double fractE = 1, term = 1;
for (int i = 1; i < 20; i++) {
term *= fract / i;
fractE += term;
}
return numE * fractE;
}

Categories

Resources