I got my sample exam question in java. I saw this expression sum += sum + d in the for loop.
Here is the code:
double sum =0;
for (double d = 0; d<10; sum += sum + d) {
d += 0.1;
}
I just dont understand that part.
I only know these:
x+=1
x=x + ++x;
x=x + x++;
Thanks in advance!
(I'm glad you understand the three obfuscated statements. But please don't use them in production. The final two are undefined in C and C++).
sum += a is shorthand for sum = sum + a for any a (neglecting any subtle differences due to implicit type conversions).
So sum += sum + d is sum = sum + sum + d; which simplifies to
sum = 2 * sum + d;
If to be more accurate, sum += a is not same to sum = sum + a, there is a type cast to type of sum. Let's consider the next example:
short x = 3;
x += 4.6;
It's the same to
short x = 3;
x = (short)(x + 4.6);
But not to x = x + 4.6
So, we have type cast to the type of sum. For more details read
JLS:
A compound assignment expression of the form E1 op= E2 is equivalent
to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1
is evaluated only once.
From the operators precedence, you can see that + (additive) operator has higher precedence than += (assignment) operator, so we first evaluate the sum + d part, let's call this result sumplusd, we get :
sum += sumplusd
Then we evaluate +=, that is increment the variable on the left part of the expression by the value on the right part, we get :
sum = sum + sumplusd, which reads sum = sum + (sum + d), which reads sum = sum*2 + d .
To simplify the whole mess, including the do loop:
double sum = 0.0;
double d = 0.0;
while ( d < 10.0 )
{
sum = 2.0*sum + d
d = d + 0.1;
}
Since, sum + = "any variable or constant" is equivalent to sum = sum + "variable or constant". Thus, sum+=sum+d would be same as sum = sum + ( sum + d ).
Related
What is Cardano Triplet ?
If a set of any three positive integers, let's say a, b and c satisfies the condition
cbrt(a + b(sqrt(c)) + cbrt(a - b(sqrt(c)) == 1
Explanation.
if sum of Cubic Root of a + (b * square root of c) and Cubic root of a - (b * square root of c) equals 1 then (a, b, c) is said to be a Cardano triplet.
cbrt represents Cubic Root and sqrt means Square Root.
A integer n will be given, so the numbers a, b and c that we take when added should be lesser than or equal to n.
In short a + b + c <= n.
Constraint : n <= 2^31 -1.
Problem
I've already done something which finds out the correct triplets but when the value of n is greater than 1000 the program runs forever.
public static void cardanoTriplets(long n) {
DecimalFormat decimalFormat = new DecimalFormat("#.###");
long numberOfPairs = 0;
for (long a = 0; a <= n; a++) {
for (long b = 0; b <= n; b++) {
for (long c = 0; c <= (n - a - b); c++) {
if ((a + b + c) == n) {
double val = b * Math.sqrt(c);
double LHS = Double.parseDouble(decimalFormat.format(Math.cbrt(a + val)));
double RHS = Double.parseDouble(decimalFormat.format(Math.cbrt(a - val)));
double addedVal = LHS + RHS;
//System.out.println("RHS and LHS -: ( " + RHS + " , " + LHS + " )");
if (addedVal == 1.0d) {
numberOfPairs++;
//System.out.println(a);
//System.out.println(b);
//System.out.println(c + "\n");
}
}
}
}
}
System.out.println(numberOfPairs);
}
Results
When I pass the value of n as 8, on average the time taken to find the cardano triplet is 31ms and sometimes as low as 16ms. The result was accurate and the result is just one and the triplet is (2, 1, 5).
But when I pass the value of n as 1000, it increases to about 1015ms and the result are not as accurate. It misses out almost 19 triplets. Total number of triplets are 149 for n == 1000.
When the value of n > 1000, let's say 5000, it took 29271ms which is 29 seconds approx and the triplets found are 3364.
Is there any way to reduce time taken to a reasonable amount like less than 5 seconds ?
If so how ?
My Device Specs :
Processor : AMD Ryzen 5 3500U Quad Core
RAM : 8 GB
IDE used : IntelliJ IDEA v2021.2.3 (Community Edition)
Thank you :)
This is a number-theoretical problem; using an imprecise floating point is obviously wrong.
The correct solution requires some math insight. Cardano's name is a great hint.
The expression
cbrt(a + b(sqrt(c)) + cbrt(a - b(sqrt(c))
describes a root of a certain cubic equation. Specifically, the roots of an equation
x^3 + px - q = 0
are
cbrt(q/2 + sqrt((q/2)^2 + (p/3)^3)) + cbrt(q/2) - sqrt(q/2)^2 + (p/3)^3))
Comparing with your problem statement, conclude that a = q/2, and c*b^2 = (q/2)^2 + (p/3)^3
Since a is an integer, q must be even, and since b, c are also integers, p must be divisible by 3. Therefore we are interested in the equations
x^3 + 3ux - 2a = 0
having 1 as a root. That narrows the problem down to searching u, v such that 1 + 3u - 2a = 0. Here u^3 + a^2 = b^2*c. Notice that u must be odd.
All these observations lead to a (pseudo)code:
for u in range(1, n, 2)
a = (1 + 3u)/2
t = u^3 + a^2
find the largest b such that b^2 divides t
c = t / b^2
if a + b + c < n
they are a Cardano triplet
Your first problem, is the loop-in-loop-in-loop what will take 1.000.000.000 rounds for n=1000.
As you know already that n = a + b + c, you can take one loop out. the c-loop
and rewrite as:
for (long a = 0; a <= n; a++) {
for (long b = 0; b <= (n - a); b++) {
long c = n - a - b;
so you go from n * n * n -> n * n
If the equation is n => a + b + c (as in your problem statement), you can use:
for (long a = 0; a <= n; a++) {
for (long b = 0; b <= (n - a); b++) {
for (long c = 0; c <= (n - a - b); c++) {
Second, you are doing a format to a decimal and then convert back to double where as the Math.cbrt gives already a double. I would suggest not doing so.
The problem of "missing 19 triplets" is related to the point above. You only accept 1.0d as the correct answer, there in the previous step you did formatting on the doubles (most likely giving rounding issues). Even if you would take out the formatting, I believe it is better to allow for a bit more rounding error..
something like:
if (0.999 < addedVal && addedVal < 1.001)
However, I have no idea on the math of this equation as there must be a reason why you say there are 149 triplets.. Depending on the rounding for sure you have different answers... I believe there is something like mathemathical proof the triplets are 1.
Last what you can do: I believe the calculation of the Math.cbrt is not that fast. You are repeating this a lot. You can keep track of your calculation by placing the result of the Math,cbrt in a HashSet. The Key is the input and the Value the result of the Math.cbrt.
So first check if you have the Key already in the HashSet, if not calculate the cbrt and place it, if already available us it..
I have implemented a function to find the trapezoid rule of a given function, the function produces poor results for
.
When I try to calculate the trapezoid rule with n < 8 it produces a value much larger than the actual area, which is unexpected, I have graphed f(x) and drawn how I believe the first few numbers of trapezoids would look, and they all should be producing less than the target area.
However, as n increases, the error becomes lower and lower and at n = 10000000 it is within a 0.001 of the solution.
private interface MathFunc {
double apply(double value);
}
private static final double A = 1;
private static final double B = 9;
public static void main(String args[]) {
MathFunc func = (x) -> Math.log(x) / Math.log(2);
double realValue = 16.98776493946568;
for(int i = 1; i <= 8; i*=2) {
double value = trapezoidRule(A, B, func, i);
System.out.println(i + " Trapezoid Summation for f(x): " + value);
double absError = Math.abs(value - realValue);
System.out.println("Abs Error: " + absError);
System.out.println("% Error: " + (absError/realValue)*100);
System.out.println();
}
}
static double trapezoidRule(double a, double b, MathFunc f, double n) {
double deltaX = (b-a)/n;
double i = 0;
double sum = 0.0;
while( i++ <= n ) {
if(i == 0 || i == n) {
sum += f.apply(a + (i*deltaX));
} else {
sum += 2 * f.apply(a + (i*deltaX));
}
}
return (deltaX * sum) / 2.0;
}
If you step through trapezoidRule for n = 1 in a debugger, you'll see that the loop is executed for i=1 and i=2. Since i=2 is treated as a midpoint, it is counted twice.
Why is the loop executed for wrong values of i? The expression i++ uses the post-increment operator, which increments the variable after returning its value. You should be using a pre-increment operator ++i, or a for loop like any sane person:
for (double i = 0; i <= n; i++) {
while( i++ <= n )
Was causing an issue, as it was doing an extra iteration.
while( i++ < n )
Produces the correct values.
The following code is designed to factorize a number typed into the variable x.
public class testMod{
public static void main(String[]args){
double x = 11868681080091051216000;
StringBuilder output = new StringBuilder("1 * ");
for(double y = 2; y <= x; y++){
while (x % y == 0) {
System.out.print("Calculating... \n");
String printNumber = y + " * ";
x = x / y;
output.append(printNumber);
System.out.print(output.substring(0, output.length() - 2) + "\n");
}
}
}
}
The problem is that the compiler treats 11868681080091051216000 as an int, regardless of the attempt to assign it to a double. As such, it's out of range.
To specify a double literal, you can simply append D to the end – but do note that you'll lose precision this way:
double x = 11868681080091051216000D;
System.out.println(x); // prints 186868108009105E22
If you need the full precision, you can use a BigInteger instead, but you'll still need to specify that number in expressions that Java can handle, such as a product of its factors.
The question was basically to calculate e^x without inbuilt functions in Java.
The sequence to code was e^x = 1+x+x2/2!+x3/3!+x4/4!+ ...
Here was my attempt at the question:
public static void myexp(double x, double i){
double j = 1.0;
double sum = x;
while (j <= i){
j = j + 1;
sum = sum + (sum * (x / (j)));
System.out.println(sum + 1 + x);
}
}
public static void main(String[] args) {
double x = 1;
double i = 5.0;
myexp(x, i);
}
Now it wasn't working, and eventually I gave in and looked up what a model answer should look like (I know, I know). Here is what it is (in the style of my code):
public static void myexp(double x, double i){
double j = 1.0;
double sum = x;
double result = 1.0;
while (j <= i){
j = j + 1;
sum = sum * (x / (j));
result = result + sum;
System.out.println(result + x);
}
}
Now the difference is the inclusion of the 'results' variable, which delineates the summation of the sequence. However, I thought I had incorporated that when I wrote
"sum = sum+(sum*(x/(j)));".
But the machine recognises one style and not the other. What gives?
In each iteration you are supposed to add to the total sum the term
sum * x / j
where sum is the term added in the previous iteration.
This means you must store the term added in the previous iteration in a separate variable.
If you use the same variable for the total result (which is supposed to be the sum of all the terms of all iterations) and for the term of the current iteration (sum), you get an entirely different result.
In other words
sum = sum + (sum * (x / (j)));
is not equivalent to
sum = sum * (x / (j));
result = result + sum;
since the value of sum depends on the previous value of sum, and therefore you can't eliminate that variable.
This question already has answers here:
Integer division: How do you produce a double?
(11 answers)
Closed 10 years ago.
So i am having a difficult time trying to figure out how to get the values to come out properly. All of the math is correct, but it only stating whole numbers. For example, when i input the numbers 87, 42, and 94, the average should come out 74.3 repeating. Yet it only comes out 74.0 for me. Same goes with the average for lowest score.
Scanner keyboard = new Scanner(System.in);
int a;
int b;
int c;
double grade;
double avg;
double avg2 = 0;
System.out.print("Enter score number 1: ");
a = keyboard.nextInt();
System.out.print("Enter score number 2: ");
b = keyboard.nextInt();
System.out.print("Enter score number 3: ");
c = keyboard.nextInt();
avg = ((a + b + c) / 3);
System.out.println("The average is: " + avg);
if (a < b && a < c)
{
System.out.println("The lowest score was: " + a);
System.out.println("The average without the lowest score is: " + ((b + c) / 2));
avg2 = ((b + c) / 2);
}
if (b < a && b < c)
{
System.out.println("The lowest score was: " + b);
System.out.println("The average without the lowest score is: " + ((a + c) / 2));
avg2 = ((a + c) / 2);
}
if (c < a && c < b)
{
System.out.println("The lowest score was: " + c);
System.out.println("The average without the lowest score is: " + ((a + b) /2));
avg2 = ((a + b) / 2);
}
You must cast the sum in the numerator of your avg expression to a double or use a double in the denominator:
avg = ((double)(a + b + c) / 3);
or
avg = ((a + b + c) / 3.0);
When you use all ints on the right hand side, the answer is calculated as an int before it is assigned to the double. This is why you are getting a rounded answer.
To fix, one option is to add decimal places to all your denominators like so
avg = ((a + b + c) / 3.0d);
This will force the operation to happen in double
A division between two ints will return an int. To cause the division that returns double, one of the operands must be a double, like so:
avg = ((a + b + c) / 3.0);
This is how operators work in Java. If you have any arithmetic operation, say division, in which both operands are integer then the operator will yield an integer. It is possible to loose some information in such division operations.
In your case, though you are assigning the result to a variable of type double, the assignment operator is executed after division operator is finished.
If you do not want to loose information, you can typecast any of the operand to desired type (in your case, to double).
avg = (double)(a + b + c) / 3;
Or
avg = (a + b + c) / (double)3;
Now, in above statements, division operator has two operands of different types. So the result will of type which is superior among the two.