Erroneous behaviour of Java 8 Stream.sum() - java

Today while solving this question on HackerRank I used Array stream .sum() function to sum all the entries and proceeded with my algorithm. But for sum reason I found that my algorithm fails for some cases. I used diff to find out it passes 99% cases and for 1% the output is nearly equal but is less than the original answer. That's why I replaced the stream .sum() with a for loop and unexpectedly it passed all the test cases. I tried but couldn't ascertain this uncertain behaviour.
My implementation using stream.sum() :
public class MandragoraForest {
public static void main(String[] args) {
InputReader in = new InputReader(System.in);
for (int i = in.nextInt(); i > 0; i--) {
int number = in.nextInt();
int[] h = new int[number];
for (int j = 0; j < number; j++) h[j] = in.nextInt();
System.out.println(new MandragoraForestSolver().solve(h));
}
}
}
class MandragoraForestSolver {
public long solve(int[] h) {
if (h.length==1) return h[0];
Arrays.parallelSort(h);
long sum = Arrays.stream(h)
.sum();
long ans = -1;
for (long i=0, strength = 2; i<h.length; i++, strength++) {
sum -= h[(int)i];
ans = Math.max(ans, strength * sum);
}
return ans;
}
}
Implementation without Java stream :
public class MandragoraForest {
public static void main(String[] args) {
InputReader in = new InputReader(System.in);
for (int i = in.nextInt(); i > 0; i--) {
int number = in.nextInt();
int[] h = new int[number];
long sum = 0;
for (int j = 0; j < number; j++) {
h[j] = in.nextInt();
sum += h[j];
}
System.out.println(new MandragoraForestSolver().solve(h, sum));
}
}
}
class MandragoraForestSolver {
public long solve(int[] h, long sum) {
if (h.length==1) return h[0];
Arrays.parallelSort(h);
long ans = -1;
for (long i=0, strength = 2; i<h.length; i++, strength++) {
sum -= h[(int)i];
ans = Math.max(ans, strength * sum);
}
return ans;
}
}
Is there something that I'am missing out ? What could be the reason for this behaviour?

There is one significant difference between using a stream and a loop - the possibility of arithmetic overflow.
Arrays.stream(int[]) returns an IntStream, whose sum() method returns an int result. If the sum exceeds Integer.MAX_VALUE, a silent integer overflow will occur.
However your loop sums by adding int values to a long total, which would not suffer from arithmetic overflow.
The sum of integers in one of the tests must exceed Integer.MAX_VALUE, testing that a long is used to (correctly) calculate the total.
If you want to use a stream to sum, you need to convert the IntStream to a LongStream, which you can do like this:
long sum = Arrays.stream(big).asLongStream().sum();

Related

For-loop returning wrong results

I am getting wrong results resolving below task:
Generalized harmonic numbers. Write a program GeneralizedHarmonic.java that takes two integer command-line arguments n and r and uses a for loop to compute the nth generalized harmonic number of order r, which is defined by the following formula:
formula
public class GeneralizedHarmonic {
public static void main(String[] args) {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
int i;
double sum = 0;
for (i = 0; i <= a; i++) {
sum += 1 / Math.pow(i, b);
}
System.out.println(sum);
}
}
This is my code but I could not get the correct test output.The output result is always Infinity.
test outputs
You have initliazed int i = 0 in for-loop for (i = 0; i <= a; i++) and so the first element of your harmonic number isn't , but .
The code that works:
public class GeneralizedHarmonic {
public static void main(String[] args) {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
double sum = 0;
for (int i = 1; i <= a; i++) {
sum += 1 / Math.pow(i, b);
}
System.out.println(sum);
}
}

How can I print out n numbers that satisfy the condition

I have written a code that would return either 1 or 4 as the output, and here it is
public static int findSum(int k) {
int sum = 0;
boolean foundNonZero = false;
for (; k != 0; k /= 10) {
if (foundNonZero) {
sum += (k % 10)*(k % 10);
} else {
foundNonZero = k % 10 != 0;
}
}
return sum;
}
Now, I'm trying to write a function public static long[] firstK(int k) that would return k numbers starting from 0 that would satisfy the condition that findsum = 1.
I'm struggling to understand how to do it, despite reading Java syntax and information. and here is my code so far:
public static long[] firstK(int k) {
while (int x = 0;) {
if (findSum(x) = 1;)
System.out.println(x);
}
I know that int(k) isn't used in this, but I have no idea how to implement it. Any help would be greatly appreciated :)
Thank you,
Dave Shah, MUIC
Maybe something like this:
public static List<Integer> firstK(int k) {
List<Integer> result = new ArrayList<>();
for (int x = 0 ; result.size() < k ; x++)
if (findSum(x) == 1)
result.add(k);
return result;
}
If you really want an array rather than a List, I would still use a List to compute the result. I would then create an array from that list and return that as the function's result to have the function return a int[] or long[]. I can't see why you'd want to return long[] or List<Long> rather than int[] or List<Integer>, I doubt the code involved would ever be given the chance to iterate past the maximum integer value.
UPDATE: Here's a complete example that uses an array throughout:
public class Test {
public static int findSum(int k) {
int sum = 0;
boolean foundNonZero = false;
for (; k != 0; k /= 10) {
if (foundNonZero) {
sum += (k % 10)*(k % 10);
} else {
foundNonZero = k % 10 != 0;
}
}
return sum;
}
public static long[] firstK(int k) {
long[] result = new long[k];
int i = 0;
for (int x = 0; i < k; x++)
if (findSum(x) == 1)
result[i++] = x;
return result;
}
public static void main(String[] args) {
long[] r = firstK(5);
System.out.println(Arrays.toString(r));
}
}
Result:
[11, 12, 13, 14, 15]
The use of an array during the operation is fine because you do know the size of that array up front. You often don't, in which case it is usually cleaner to use a List to collect terms, and then convert to an array at the end. I did it this way initially out of habit. In practice, at least in my case, I pretty much never use arrays due to them being less flexible. They ARE more compact and can perform better, but it is rarely the case that the difference matters.

How to find the sum of factorial of all numbers in a series?

I want to create a program to find the sum of factorial of all numbers in a series till 20.
I have to find 's' in s = 1 + (1*2) + (1*2*3) + ...(1*2*3...20).
I tried a program but it is not working. I am using BlueJ IDE.
int a =1;
int s = 0;
for(int i = 1; i <= 10; i++)
{
while (i >0)
{
a = a * i;
i--;
}
s = s+a;
}
System.out.println(s);
The compiler does not show any error message but when I run the program the JVM(Java Virtual Machine) keeps loading and the output screen does not show up.
You can try this one :
public class Main
{
public static void main (String[]args)
{
int fact = 1;
int sum = 0;
int i, j = 1;
for (i = 1; i <= 20; i++)
{
for (j = 1; j <= i; j++)
{
fact = fact * j;
}
sum += fact;
System.out.println ("sum = " + sum);
fact = 1;
}
}
}
Always give proper variable name and Try to avoid to use same variable at different places i.e you have use variable i in outer and inner loop which is not good habit.
You should be using a different loop variable name in your inner loop, and you also need to use a long to store your sum. In fact, I would first write a method to multiply up to a number in the series. Like,
static long multiplyTo(int n) {
long r = 1L;
for (int i = 2; i <= n; i++) {
r *= i;
}
return r;
}
Then you can invoke that and calculate your sum with a simple loop. Like,
long sum = 0L;
for (int i = 1; i <= 20; i++) {
sum += multiplyTo(i);
}
System.out.println(sum);
I get
2561327494111820313
Using streams:
long s = LongStream.rangeClosed(1, 20)
.map(upper -> LongStream.rangeClosed(1, upper)
.reduce(1, (a, b) -> a * b))
.sum();
System.out.println(s);
Prints 2561327494111820313
I did the same program using Scanner Class
import java.util.*;
class Sum_Factorial
{
public static void main()
{
Scanner in = new Scanner(System.in);
int i; //Denotes Integer
int n; //Denotes Number
int f=1; //Denotes Factorial
int s=0; //Denotes Sum
System.out.println("Enter the value of N : ");
n=in.nextInt();
for(i=1; i<=n; i++)
{
f=f*i;
s=s+f;
}
System.out.println("Sum of the factorial numbers is "+s);
}
}

Return the amount of numbers below average

I am trying to write a program that returns the amount of numbers less than the average
For example, if I have the numbers 2, 3 and 4, the average would be (2.1+3.6+4.2)/3 = 3.3 and since 2.3 is below average it would return 1 as there is one number below the average.
I am getting an error that says
Type mismatch: cannot convert from double[] to int
My code:
public static void main(String[] args) {
double[] numbers = {2.1, 3.6, 4.2};
System.out.println(belowaverage(numbers));
}
public static int belowaverage(double[] ba) {
double sum = 0;
double average = 0;
for(int i = 0;i<ba.length;i++){
sum = sum + ba[i];
average = sum / ba.length;
if(ba[i]<average){
return ba;
}
}
You're trying to return the array ba which is the array holding your input data instead of the count.
You need to leave the computation of the average in your current for loop and then create a second for loop and an int count variable which you will increment each time you find a number in the ba array that is smaller than the average. Then outside of that loop you return count.
Also this line:
average = sum / ba.length;
Has to be outside of the first loop.
#Edit: others provided some code but it had either logical or compile time errors (not all of them I guess, the ones I checked) so here's a working version:
public static int belowaverage(double[] ba) {
double sum = 0;
double average = 0;
int count = 0;
for(int i = 0; i < ba.length; i++) {
sum = sum + ba[i];
}
average = sum / ba.length;
for(int i = 0; i < ba.length; i++){
if (ba[i] < average) {
count++;
}
}
return count;
}
You don't need to cast length to double as sum is of type double so the result will be promoted to the bigger type.
public static void main(String[] args) {
double[] numbers = {2.1, 3.6, 4.2};
System.out.println(belowaverage(numbers));
}
public static int belowaverage(double[] ba) {
double sum = 0;
int length = ba.length;
for (int i = 0; i < length; i++) {
sum += ba[i];
}
double average = sum / length;
int belowAvgCount = 0;
for (int i = 0; i < length; i++) {
if (ba[i] < average) {
belowAvgCount++;
}
}
return belowAvgCount;
}
This isn't going to work using only a single for loop, because you can't possibly compare anything to the average until you've calculated it.
Try separating your calculation of the average and the counting of terms below the average into two different loops:
public static int belowaverage(double[] ba) {
double sum = 0;
double average = 0;
for(double b : ba){
sum += b;
}
average = sum / ba.length;
int count = 0;
for(double b : ba){
if(b < average){
count++;
}
}
return count;
}
You need to work out the sum first, then compute the average and then count how many below this threshold.
try
public static int belowaverage(double[] ba) {
double sum = 0;
double average = 0;
int count = 0;
for(int i = 0;i<ba.length;i++){
sum = sum + ba[i];
}
average = sum / ba.length;
for(int i = 0;i<ba.length;i++){
if (ba[i] < average) count++;
}
return count;
}

Find factorial of large numbers in Java

I tried to find the factorial of a large number e.g. 8785856 in a typical way using for-loop and double data type.
But it is displaying infinity as the result, may be because it is exceeding its limit.
So please guide me the way to find the factorial of a very large number.
My code:
class abc
{
public static void main (String[]args)
{
double fact=1;
for(int i=1;i<=8785856;i++)
{
fact=fact*i;
}
System.out.println(fact);
}
}
Output:-
Infinity
I am new to Java but have learned some concepts of IO-handling and all.
public static void main(String[] args) {
BigInteger fact = BigInteger.valueOf(1);
for (int i = 1; i <= 8785856; i++)
fact = fact.multiply(BigInteger.valueOf(i));
System.out.println(fact);
}
You might want to reconsider calculating this huge value. Wolfram Alpha's Approximation suggests it will most certainly not fit in your main memory to be displayed.
This code should work fine :-
public class BigMath {
public static String factorial(int n) {
return factorial(n, 300);
}
private static String factorial(int n, int maxSize) {
int res[] = new int[maxSize];
res[0] = 1; // Initialize result
int res_size = 1;
// Apply simple factorial formula n! = 1 * 2 * 3 * 4... * n
for (int x = 2; x <= n; x++) {
res_size = multiply(x, res, res_size);
}
StringBuffer buff = new StringBuffer();
for (int i = res_size - 1; i >= 0; i--) {
buff.append(res[i]);
}
return buff.toString();
}
/**
* This function multiplies x with the number represented by res[]. res_size
* is size of res[] or number of digits in the number represented by res[].
* This function uses simple school mathematics for multiplication.
*
* This function may value of res_size and returns the new value of res_size.
*/
private static int multiply(int x, int res[], int res_size) {
int carry = 0; // Initialize carry.
// One by one multiply n with individual digits of res[].
for (int i = 0; i < res_size; i++) {
int prod = res[i] * x + carry;
res[i] = prod % 10; // Store last digit of 'prod' in res[]
carry = prod / 10; // Put rest in carry
}
// Put carry in res and increase result size.
while (carry != 0) {
res[res_size] = carry % 10;
carry = carry / 10;
res_size++;
}
return res_size;
}
/** Driver method. */
public static void main(String[] args) {
int n = 100;
System.out.printf("Factorial %d = %s%n", n, factorial(n));
}
}
Hint: Use the BigInteger class, and be prepared to give the JVM a lot of memory. The value of 8785856! is a really big number.
Use the class BigInteger. ( I am not sure if that will even work for such huge integers )
Infinity is a special reserved value in the Double class used when you have exceed the maximum number the a double can hold.
If you want your code to work, use the BigDecimal class, but given the input number, don't expect your program to finish execution any time soon.
The above solutions for your problem (8785856!) using BigInteger would take literally hours of CPU time if not days. Do you need the exact result or would an approximation suffice?
There is a mathematical approach called "Sterling's Approximation
" which can be computed simply and fast, and the following is Gosper's improvement:
import java.util.*;
import java.math.*;
class main
{
public static void main(String args[])
{
Scanner sc= new Scanner(System.in);
int i;
int n=sc.nextInt();
BigInteger fact = BigInteger.valueOf(1);
for ( i = 1; i <= n; i++)
{
fact = fact.multiply(BigInteger.valueOf(i));
}
System.out.println(fact);
}
}
Try this:
import java.math.BigInteger;
public class LargeFactorial
{
public static void main(String[] args)
{
int n = 50;
}
public static BigInteger factorial(int n)
{
BigInteger result = BigInteger.ONE;
for (int i = 1; i <= n; i++)
result = result.multiply(new BigInteger(i + ""));
return result;
}
}
Scanner r = new Scanner(System.in);
System.out.print("Input Number : ");
int num = r.nextInt();
int ans = 1;
if (num <= 0) {
ans = 0;
}
while (num > 0) {
System.out.println(num + " x ");
ans *= num--;
}
System.out.println("\b\b=" + ans);
public static void main (String[] args) throws java.lang.Exception
{
BigInteger fact= BigInteger.ONE;
int factorialNo = 8785856 ;
for (int i = 2; i <= factorialNo; i++) {
fact = fact.multiply(new BigInteger(String.valueOf(i)));
}
System.out.println("Factorial of the given number is = " + fact);
}
import java.util.Scanner;
public class factorial {
public static void main(String[] args) {
System.out.println("Enter the number : ");
Scanner s=new Scanner(System.in);
int n=s.nextInt();
factorial f=new factorial();
int result=f.fact(n);
System.out.println("factorial of "+n+" is "+result);
}
int fact(int a)
{
if(a==1)
return 1;
else
return a*fact(a-1);
}
}

Categories

Resources