Context: I'm trying to calculate factorials for very large n using the BigInteger class in Java (for n>100,000) and so far this what I'm doing:
Produce all primes less than or equal to n using Sieve of Erasthones
Find to which powers they will be raised.
Raise all the numbers to the respective powers.
Use a divide and conquer recursive method to multiply them all.
From the research I've done on the internet, this is asymptotically faster than simply multiplying all k up to n. However I've noticed that the slowest part of my implementation is the part where I multiply all the prime powers. My questions are:
Is there a faster way to calculate the product of lots of numbers?
Can my implementation be improved ?
Code:
public static BigInteger product(BigInteger[] numbers) {
if (numbers.length == 0)
throw new ArithmeticException("There is nothing to multiply!");
if (numbers.length == 1)
return numbers[0];
if (numbers.length == 2)
return numbers[0].multiply(numbers[1]);
BigInteger[] part1 = new BigInteger[numbers.length / 2];
BigInteger[] part2 = new BigInteger[numbers.length - numbers.length / 2];
System.arraycopy(numbers, 0, part1, 0, numbers.length / 2);
System.arraycopy(numbers, numbers.length / 2, part2, 0, numbers.length - numbers.length / 2);
return product(part1).multiply(product(part2));
}
Note that BigInteger uses the karatsuba algorithm for multiplication.
I know that there are lots of questions about calculating factorials. But mine is about calculating the product of BigIntegers for which there is not much resource. (I've seen someone say "Use Divide and Conquer method", but I don't remember where, and I haven't seen any implementation around.
One way to improve the performance is to do the following:
Sort your array of numbers you need to multiply together
Create two new lists: a and b.
For each number in the input list that you need to multiply, it is likely to appear more than once. Let's say number v_i appears n_i times. Then add v_i to the a n_i / 2 times (rounded down). If n_i is odd, add v_i once to b as well.
To compute the result, do:
BigInteger A = product(a);
BigInteger B = prudoct(b);
return a.multiply(a).multiply(b);
To see how it works, consider your input array is [2, 2, 2, 2, 3, 3, 3]. So, there are four 2s and three 3s. Arrays a and b will correspondingly be
a = [2, 2, 3]
b = [3]
Then you will recursively call to compute the product of these. Note that we reduced the number of numbers that we want to multiply from 7 to 4, almost by a factor of two. The trick here is that for numbers that occur many times, we can compute the product of only half of them, and then raise it to the power of two. Very similar to how the power of a number can be computed in O(log n) time.
I propose another idea, the pow algorithm is very fast, you can compute the all primes with the exponent, like this:
11! -> {2^10, 3^5, 5^2, 7^1, 11^1}
You can compute all primes power , and then use divide and conquer to multiply all of them.
The implementation:
private static BigInteger divideAndConquer(List<BigInteger> primesExp, int min, int max){
BigInteger result = BigInteger.ONE;
if (max - min == 1){
result = primesExp.get(min);
} else if (min < max){
int middle = (max + min)/2;
result = divideAndConquer(primesExp, min, middle).multiply(divideAndConquer(primesExp, middle, max));
}
return result;
}
public static BigInteger factorial(int n) {
// compute pairs: prime, exp
List<Integer> primes = new ArrayList<>();
Map<Integer, Integer> primeTimes = new LinkedHashMap<>();
for (int i = 2; i <= n; i++) {
int sqrt = Math.round((float) Math.sqrt(i));
int value = i;
Iterator<Integer> it = primes.iterator();
int prime = 0;
while (it.hasNext() && prime <= sqrt && value != 0) {
prime = it.next();
int times = 0;
while (value % prime == 0) {
value /= prime;
times++;
}
if (times > 0) {
primeTimes.put(prime, times + primeTimes.get(prime));
}
}
if (value > 1) {
Integer times = primeTimes.get(value);
if (times == null) {
times = 0;
primes.add(value);
}
primeTimes.put(value, times + 1);
}
}
// compute primes power:
List<BigInteger> primePows = new ArrayList<>(primes.size());
for (Entry<Integer,Integer> e: primeTimes.entrySet()) {
primePows.add(new BigInteger(String.valueOf(e.getKey())).pow(e.getValue()));
}
// it multiply all of them:
return divideAndConquer(primePows, 0, primePows.size());
}
Probably the fastest approach :
Sequence.java
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public final class Sequence {
private final List<BigInteger> elements;
private Sequence(List<BigInteger> elements) {
this.elements = elements;
}
public List<BigInteger> getElements() {
return elements;
}
public int size() {
return elements.size();
}
public Sequence subSequence(int startInclusive, int endExclusive) {
return subSequence(startInclusive, endExclusive, false);
}
public Sequence subSequence(int startInclusive, int endExclusive, boolean sync) {
return Sequence.of(elements.subList(startInclusive, endExclusive), sync);
}
public void addLast(BigInteger element) {
elements.add(element);
}
public BigInteger removeLast() {
return elements.remove(size() - 1);
}
public BigInteger sum() {
return sum(false);
}
public BigInteger sum(boolean parallel) {
return parallel
? elements.parallelStream().reduce(BigInteger.ZERO, BigInteger::add)
: elements.stream().reduce(BigInteger.ZERO, BigInteger::add);
}
public BigInteger product() {
return product(false);
}
public BigInteger product(boolean parallel) {
return parallel
? elements.parallelStream().reduce(BigInteger.ONE, BigInteger::multiply)
: elements.stream().reduce(BigInteger.ONE, BigInteger::multiply);
}
public static Sequence range(int startInclusive, int endExclusive) {
return range(startInclusive, endExclusive, false);
}
public static Sequence range(int startInclusive, int endExclusive, boolean sync) {
if (startInclusive > endExclusive) {
throw new IllegalArgumentException();
}
final List<BigInteger> elements = sync ? Collections.synchronizedList(new ArrayList<>()) : new ArrayList<>();
for (; startInclusive < endExclusive; startInclusive++) {
elements.add(BigInteger.valueOf(startInclusive));
}
return new Sequence(elements);
}
public static Sequence of(List<BigInteger> elements) {
return of(elements, false);
}
public static Sequence of(List<BigInteger> elements, boolean sync) {
return new Sequence(sync ? Collections.synchronizedList(elements) : elements);
}
public static Sequence empty() {
return empty(false);
}
public static Sequence empty(boolean sync) {
return of(new ArrayList<>(), sync);
}
}
FactorialCalculator.java
import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;
public final class FactorialCalculator {
private static final int CHUNK_SIZE = Runtime.getRuntime().availableProcessors();
public static BigInteger fact(int n) {
return fact(n, false);
}
public static BigInteger fact(int n, boolean parallel) {
if (n < 0) {
throw new IllegalArgumentException();
}
if (n <= 1) {
return BigInteger.ONE;
}
Sequence sequence = Sequence.range(1, n + 1);
if (!parallel) {
return sequence.product();
}
sequence = parallelCalculate(splitSequence(sequence, CHUNK_SIZE * 2));
while (sequence.size() > CHUNK_SIZE) {
sequence = parallelCalculate(splitSequence(sequence, CHUNK_SIZE));
}
return sequence.product(true);
}
private static List<Sequence> splitSequence(Sequence sequence, int chunkSize) {
final int size = sequence.size();
final List<Sequence> subSequences = new LinkedList<>();
int index = 0, targetIndex;
while (index < size) {
targetIndex = Math.min(index + chunkSize, size);
subSequences.add(sequence.subSequence(index, targetIndex, true));
index = targetIndex;
}
return subSequences;
}
private static Sequence parallelCalculate(List<Sequence> sequences) {
final Sequence result = Sequence.empty(true);
sequences.parallelStream().map(s -> s.product(true)).forEach(result::addLast);
return result;
}
}
Test :
public static void main(String[] args) {
// warm up
for (int i = 0; i < 100; i++) {
FactorialCalculator.fact(10000);
}
int n = 1000000;
long start = System.currentTimeMillis();
FactorialCalculator.fact(n, true);
long end = System.currentTimeMillis();
System.out.printf("Execution time = %d ms", end - start);
}
Result :
Execution time = 3066 ms
OS : Win 10 Pro 64-bit
CPU : Intel Core i7-4700HQ # 2.40GHz 2.40GHz
Related
It is a code that gets prime numbers, I have made it as efficient as I could, but the problem is that I can't transform it to BigInteger, as long can't hold that much information; here the code:
public class p3{
static long perfectNumber;
static long mersenne;
public static void main(String[] args) {
long p = 2;
while (true) {
if( p % 2 == 0&&p!=2){
p++;
}
else{
if (isPrime(p) == true) {
mersenne = (long) (Math.pow(2, p) - 1);
if (isPrime(mersenne) == true) {
perfectNumber = (long) Math.pow(2, (p - 1)) * mersenne;
System.out.println(perfectNumber);
}
}
p+=1;
}
}
}
private static boolean isPrime(long testPrime) {
for (long i = 3; i < Math.sqrt(testPrime); i += 2) {
if (testPrime % i == 0) {
return false;
}
}
return true;
}
}
I've tried to use BigInteger but code is not working, as I can't use
BigInteger exponents with pow
You don't need to. The exponents don't need to be nearly as large as the mersenne primes and perfect numbers. They can have their own independent isPrime() test. In fact, they need to be int, instead of long, to satisfy BigInteger.pow().
Below is what you asked for, but may not be what you want. I doubt you'll get more then one additional perfect number beyond your original code due to time constraints which is why #WJS is pushing you in a different direction.
import java.math.BigInteger;
public class p3 {
static BigInteger TWO = new BigInteger("2");
static BigInteger THREE = new BigInteger("3");
public static void main(String[] args) {
int p = 2;
while (true) {
if (isPrime(p)) {
BigInteger mersenne = TWO.pow(p).subtract(BigInteger.ONE);
if (isPrime(mersenne)) {
System.out.println(TWO.pow(p - 1).multiply(mersenne));
}
}
p += (p == 2) ? 1 : 2;
}
}
private static boolean isPrime(BigInteger number) {
if (number.mod(TWO).equals(BigInteger.ZERO)) {
return number.equals(TWO);
}
for (BigInteger i = THREE; number.compareTo(i.multiply(i)) >= 0; i = i.add(TWO)) {
if (number.mod(i).equals(BigInteger.ZERO)) {
return false;
}
}
return true;
}
private static boolean isPrime(int number) {
if (number % 2 == 0) {
return number == 2;
}
for (int i = 3; number >= i * i; i += 2) {
if (number % i == 0) {
return false;
}
}
return true;
}
}
OUTPUT
> java p3
6
28
496
8128
33550336
8589869056
137438691328
2305843008139952128
2658455991569831744654692615953842176
Your original code outputs 0 in place of the final (37 digit) number above. So the immediate issue really is that long can't hold enough information. But beyond this point, you simply can't calculate fast enough with the above algorithm.
If we do something simple-minded to my above code, like replace this line:
if (isPrime(mersenne)) {
with:
if (mersenne.isProbablePrime(10)) {
The code will spit out the first 20 perfect numbers before slowing to a crawl. Tune the certainty argument of isProbablePrime() as you see fit.
So i'm trying to generate all binaries of a size n but with the condition that only k 1s. i.e
for size n = 4, k=2, (there is 2 over 4 combinations)
1100
1010
1001
0110
0101
0011
I'm stuck and can't figure out how to generate this.
Using the basic recursive method for printing all binary sequence all that remains is to enforce your constraints:
private static void binSeq(int n, int k, String seq) {
if (n == 0) {
System.out.println(seq);
return;
}
if (n > k) {
binSeq(n - 1, k, seq + "0");
}
if (k > 0) {
binSeq(n - 1, k - 1, seq + "1");
}
}
Here's my non-recursive take on this algorithm. Because there are 2^n permutations of binary strings, we can use a for-loop to iterate through every possible string and check if the amount of "1"s is not equal to k:
private static void generate(int n, int k) {
for (int i = 0; i < Math.pow(2, n); i++) {
if (Integer.bitCount(i) != k) {
continue;
}
String binary = Integer.toBinaryString(i);
if (binary.length() < n) {
System.out.format("%0" + (n - binary.length()) + "d%s\n", 0, binary);
} else {
System.out.println(binary);
}
}
}
One approach is to generate all combinations of k values from the set of n numbers 0..n-1, and use these values to set the corresponding bits in the output.
This Q&A explains how to generate all combinations of k elements from n. With these combinations in hand, use bitwise OR of 1 << v[c][i] to produce the final result, where v[c][i] represents i-th number from combination number c.
Below is the solution using Recursion as an approach in java
public class NumberOfBinaryPatternsSpecificOnes {
static int[] bitArray = new int[]{0,1}; // kept binary bits in array
public static void main(String args[])
{
System.out.println("Below are the patterns\n");
int n = 4;
int k = 2;
drawBinaryPattern(n,"",k,0);
}
private static void drawBinaryPattern(int n,String seed,int numberOfOnes,int currentCount)
{
if(n==0)
{
if(currentCount==numberOfOnes){
System.out.println(seed);
}
return;
}
for(int j=0;j<bitArray.length;j++)
{
String temp = seed+bitArray[j];
int currentcountTemp = bitArray[j]==1?(currentCount+1):(currentCount);
if(currentcountTemp>numberOfOnes)
{
return;
}
drawBinaryPattern(n-1,temp,numberOfOnes,currentcountTemp);
}
}
}
int n = 4, k=2;
for (int i = 0; i < Math.pow(2,n) ; i++) {
int a = Integer.bitCount(i);
if (a == k) System.out.println(Integer.toBinaryString(i));
}
I think this is the simplest answer.
I'm trying to calculate the total, mean and median of an array thats populated by input received by a textfield. I've managed to work out the total and the mean, I just can't get the median to work. I think the array needs to be sorted before I can do this, but I'm not sure how to do this. Is this the problem, or is there another one that I didn't find? Here is my code:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.*;
import java.awt.event.*;
public class whileloopq extends Applet implements ActionListener
{
Label label;
TextField input;
int num;
int index;
int[] numArray = new int[20];
int sum;
int total;
double avg;
int median;
public void init ()
{
label = new Label("Enter numbers");
input = new TextField(5);
add(label);
add(input);
input.addActionListener(this);
index = 0;
}
public void actionPerformed (ActionEvent ev)
{
int num = Integer.parseInt(input.getText());
numArray[index] = num;
index++;
if (index == 20)
input.setEnabled(false);
input.setText("");
sum = 0;
for (int i = 0; i < numArray.length; i++)
{
sum += numArray[i];
}
total = sum;
avg = total / index;
median = numArray[numArray.length/2];
repaint();
}
public void paint (Graphics graf)
{
graf.drawString("Total = " + Integer.toString(total), 25, 85);
graf.drawString("Average = " + Double.toString(avg), 25, 100);
graf.drawString("Median = " + Integer.toString(median), 25, 115);
}
}
The Arrays class in Java has a static sort function, which you can invoke with Arrays.sort(numArray).
Arrays.sort(numArray);
double median;
if (numArray.length % 2 == 0)
median = ((double)numArray[numArray.length/2] + (double)numArray[numArray.length/2 - 1])/2;
else
median = (double) numArray[numArray.length/2];
Sorting the array is unnecessary and inefficient. There's a variation of the QuickSort (QuickSelect) algorithm which has an average run time of O(n); if you sort first, you're down to O(n log n). It actually finds the nth smallest item in a list; for a median, you just use n = half the list length. Let's call it quickNth (list, n).
The concept is that to find the nth smallest, choose a 'pivot' value. (Exactly how you choose it isn't critical; if you know the data will be thoroughly random, you can take the first item on the list.)
Split the original list into three smaller lists:
One with values smaller than the pivot.
One with values equal to the pivot.
And one with values greater than the pivot.
You then have three cases:
The "smaller" list has >= n items. In that case, you know that the nth smallest is in that list. Return quickNth(smaller, n).
The smaller list has < n items, but the sum of the lengths of the smaller and equal lists have >= n items. In this case, the nth is equal to any item in the "equal" list; you're done.
n is greater than the sum of the lengths of the smaller and equal lists. In that case, you can essentially skip over those two, and adjust n accordingly. Return quickNth(greater, n - length(smaller) - length(equal)).
Done.
If you're not sure that the data is thoroughly random, you need to be more sophisticated about choosing the pivot. Taking the median of the first value in the list, the last value in the list, and the one midway between the two works pretty well.
If you're very unlucky with your choice of pivots, and you always choose the smallest or highest value as your pivot, this takes O(n^2) time; that's bad. But, it's also very unlikely if you choose your pivot with a decent algorithm.
Sample code:
import java.util.*;
public class Utility {
/****************
* #param coll an ArrayList of Comparable objects
* #return the median of coll
*****************/
public static <T extends Number> double median(ArrayList<T> coll, Comparator<T> comp) {
double result;
int n = coll.size()/2;
if (coll.size() % 2 == 0) // even number of items; find the middle two and average them
result = (nth(coll, n-1, comp).doubleValue() + nth(coll, n, comp).doubleValue()) / 2.0;
else // odd number of items; return the one in the middle
result = nth(coll, n, comp).doubleValue();
return result;
} // median(coll)
/*****************
* #param coll a collection of Comparable objects
* #param n the position of the desired object, using the ordering defined on the list elements
* #return the nth smallest object
*******************/
public static <T> T nth(ArrayList<T> coll, int n, Comparator<T> comp) {
T result, pivot;
ArrayList<T> underPivot = new ArrayList<>(), overPivot = new ArrayList<>(), equalPivot = new ArrayList<>();
// choosing a pivot is a whole topic in itself.
// this implementation uses the simple strategy of grabbing something from the middle of the ArrayList.
pivot = coll.get(n/2);
// split coll into 3 lists based on comparison with the pivot
for (T obj : coll) {
int order = comp.compare(obj, pivot);
if (order < 0) // obj < pivot
underPivot.add(obj);
else if (order > 0) // obj > pivot
overPivot.add(obj);
else // obj = pivot
equalPivot.add(obj);
} // for each obj in coll
// recurse on the appropriate list
if (n < underPivot.size())
result = nth(underPivot, n, comp);
else if (n < underPivot.size() + equalPivot.size()) // equal to pivot; just return it
result = pivot;
else // everything in underPivot and equalPivot is too small. Adjust n accordingly in the recursion.
result = nth(overPivot, n - underPivot.size() - equalPivot.size(), comp);
return result;
} // nth(coll, n)
public static void main (String[] args) {
Comparator<Integer> comp = Comparator.naturalOrder();
Random rnd = new Random();
for (int size = 1; size <= 10; size++) {
ArrayList<Integer> coll = new ArrayList<>(size);
for (int i = 0; i < size; i++)
coll.add(rnd.nextInt(100));
System.out.println("Median of " + coll.toString() + " is " + median(coll, comp));
} // for a range of possible input sizes
} // main(args)
} // Utility
If you want to use any external library here is Apache commons math library using you can calculate the Median.
For more methods and use take look at the API documentation
import org.apache.commons.math3.*;
.....
......
........
//calculate median
public double getMedian(double[] values){
Median median = new Median();
double medianValue = median.evaluate(values);
return medianValue;
}
.......
For more on evaluate method AbstractUnivariateStatistic#evaluate
Update
Calculate in program
Generally, median is calculated using the following two formulas given here
If n is odd then Median (M) = value of ((n + 1)/2)th item term.
If n is even then Median (M) = value of [((n)/2)th item term + ((n)/2 + 1)th item term ]/2
In your program you have numArray, first you need to sort array using Arrays#sort
Arrays.sort(numArray);
int middle = numArray.length/2;
int medianValue = 0; //declare variable
if (numArray.length%2 == 1)
medianValue = numArray[middle];
else
medianValue = (numArray[middle-1] + numArray[middle]) / 2;
Arrays.sort(numArray);
return (numArray[size/2] + numArray[(size-1)/2]) / 2;
Arrays.sort(numArray);
int middle = ((numArray.length) / 2);
if(numArray.length % 2 == 0){
int medianA = numArray[middle];
int medianB = numArray[middle-1];
median = (medianA + medianB) / 2;
} else{
median = numArray[middle + 1];
}
EDIT: I initially had medianB setting to middle+1 in the even length arrays, this was wrong due to arrays starting count at 0. I have updated it to use middle-1 which is correct and should work properly for an array with an even length.
You can find good explanation at https://www.youtube.com/watch?time_continue=23&v=VmogG01IjYc
The idea it to use 2 Heaps viz one max heap and mean heap.
class Heap {
private Queue<Integer> low = new PriorityQueue<>(Comparator.reverseOrder());
private Queue<Integer> high = new PriorityQueue<>();
public void add(int number) {
Queue<Integer> target = low.size() <= high.size() ? low : high;
target.add(number);
balance();
}
private void balance() {
while(!low.isEmpty() && !high.isEmpty() && low.peek() > high.peek()) {
Integer lowHead= low.poll();
Integer highHead = high.poll();
low.add(highHead);
high.add(lowHead);
}
}
public double median() {
if(low.isEmpty() && high.isEmpty()) {
throw new IllegalStateException("Heap is empty");
} else {
return low.size() == high.size() ? (low.peek() + high.peek()) / 2.0 : low.peek();
}
}
}
Try sorting the array first. Then after it's sorted, if the array has an even amount of elements the mean of the middle two is the median, if it has a odd number, the middle element is the median.
Use Arrays.sort and then take the middle element (in case the number n of elements in the array is odd) or take the average of the two middle elements (in case n is even).
public static long median(long[] l)
{
Arrays.sort(l);
int middle = l.length / 2;
if (l.length % 2 == 0)
{
long left = l[middle - 1];
long right = l[middle];
return (left + right) / 2;
}
else
{
return l[middle];
}
}
Here are some examples:
#Test
public void evenTest()
{
long[] l = {
5, 6, 1, 3, 2
};
Assert.assertEquals((3 + 4) / 2, median(l));
}
#Test
public oddTest()
{
long[] l = {
5, 1, 3, 2, 4
};
Assert.assertEquals(3, median(l));
}
And in case your input is a Collection, you might use Google Guava to do something like this:
public static long median(Collection<Long> numbers)
{
return median(Longs.toArray(numbers)); // requires import com.google.common.primitives.Longs;
}
I was looking at the same statistics problems. The approach you are thinking it is good and it will work. (Answer to the sorting has been given)
But in case you are interested in algorithm performance, I think there are a couple of algorithms that have better performance than just sorting the array, one (QuickSelect) is indicated by #bruce-feist's answer and is very well explained.
[Java implementation: https://discuss.leetcode.com/topic/14611/java-quick-select ]
But there is a variation of this algorithm named median of medians, you can find a good explanation on this link:
http://austinrochford.com/posts/2013-10-28-median-of-medians.html
Java implementation of this:
- https://stackoverflow.com/a/27719796/957979
I faced a similar problem yesterday.
I wrote a method with Java generics in order to calculate the median value of every collection of Numbers; you can apply my method to collections of Doubles, Integers, Floats and returns a double. Please consider that my method creates another collection in order to not alter the original one.
I provide also a test, have fun. ;-)
public static <T extends Number & Comparable<T>> double median(Collection<T> numbers){
if(numbers.isEmpty()){
throw new IllegalArgumentException("Cannot compute median on empty collection of numbers");
}
List<T> numbersList = new ArrayList<>(numbers);
Collections.sort(numbersList);
int middle = numbersList.size()/2;
if(numbersList.size() % 2 == 0){
return 0.5 * (numbersList.get(middle).doubleValue() + numbersList.get(middle-1).doubleValue());
} else {
return numbersList.get(middle).doubleValue();
}
}
JUnit test code snippet:
/**
* Test of median method, of class Utils.
*/
#Test
public void testMedian() {
System.out.println("median");
Double expResult = 3.0;
Double result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,13.0));
assertEquals(expResult, result);
expResult = 3.5;
result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,4.0,13.0));
assertEquals(expResult, result);
}
Usage example (consider the class name is Utils):
List<Integer> intValues = ... //omitted init
Set<Float> floatValues = ... //omitted init
.....
double intListMedian = Utils.median(intValues);
double floatSetMedian = Utils.median(floatValues);
Note: my method works on collections, you can convert arrays of numbers to list of numbers as pointed here
And nobody paying attention when list contains only one element (list.size == 1). All your answers will crash with index out of bound exception, because integer division returns zero (1 / 2 = 0). Correct answer (in Kotlin):
MEDIAN("MEDIAN") {
override fun calculate(values: List<BigDecimal>): BigDecimal? {
if (values.size == 1) {
return values.first()
}
if (values.size > 1) {
val valuesSorted = values.sorted()
val mid = valuesSorted.size / 2
return if (valuesSorted.size % 2 != 0) {
valuesSorted[mid]
} else {
AVERAGE.calculate(listOf(valuesSorted[mid - 1], valuesSorted[mid]))
}
}
return null
}
},
As #Bruce-Feist mentions, for a large number of elements, I'd avoid any solution involving sort if performance is something you are concerned about. A different approach than those suggested in the other answers is Hoare's algorithm to find the k-th smallest of element of n items. This algorithm runs in O(n).
public int findKthSmallest(int[] array, int k)
{
if (array.length < 10)
{
Arrays.sort(array);
return array[k];
}
int start = 0;
int end = array.length - 1;
int x, temp;
int i, j;
while (start < end)
{
x = array[k];
i = start;
j = end;
do
{
while (array[i] < x)
i++;
while (x < array[j])
j--;
if (i <= j)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
} while (i <= j);
if (j < k)
start = i;
if (k < i)
end = j;
}
return array[k];
}
And to find the median:
public int median(int[] array)
{
int length = array.length;
if ((length & 1) == 0) // even
return (findKthSmallest(array, array.length / 2) + findKthSmallest(array, array.length / 2 + 1)) / 2;
else // odd
return findKthSmallest(array, array.length / 2);
}
public static int median(int[] arr) {
int median = 0;
java.util.Arrays.sort(arr);
for (int i=0;i<arr.length;i++) {
if (arr.length % 2 == 1) {
median = Math.round(arr[arr.length/2]);
} else {
median = (arr[(arr.length/2)] + arr[(arr.length/2)-1])/2;
}
}
return median;
}
Check out the Arrays.sort methods:
http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html
You should also really abstract finding the median into its own method, and just return the value to the calling method. This will make testing your code much easier.
public int[] data={31, 29, 47, 48, 23, 30, 21
, 40, 23, 39, 47, 47, 42, 44, 23, 26, 44, 32, 20, 40};
public double median()
{
Arrays.sort(this.data);
double result=0;
int size=this.data.length;
if(size%2==1)
{
result=data[((size-1)/2)+1];
System.out.println(" uneven size : "+result);
}
else
{
int middle_pair_first_index =(size-1)/2;
result=(data[middle_pair_first_index+1]+data[middle_pair_first_index])/2;
System.out.println(" Even size : "+result);
}
return result;
}
package arrays;
public class Arraymidleelement {
static public double middleArrayElement(int [] arr)
{
double mid;
if(arr.length%2==0)
{
mid=((double)arr[arr.length/2]+(double)arr[arr.length/2-1])/2;
return mid;
}
return arr[arr.length/2];
}
public static void main(String[] args) {
int arr[]= {1,2,3,4,5,6};
System.out.println( middleArrayElement(arr));
}
}
My task is to develop a rational class. If 500 and 1000 are my inputs, then (½) must be my output.
I have written a program on my own to find it.
Is there another best way to find the solution, or my program is already the best one?
public class Rational {
public static void main(String[] args){
int n1 = Integer.parseInt(args[0]);
int n2 = Integer.parseInt(args[1]);
int temp1 = n1;
int temp2 = n2;
while (n1 != n2){
if(n1 > n2)
n1 = n1 - n2;
else
n2 = n2 - n1;
}
int n3 = temp1 / n1 ;
int n4 = temp2 / n1 ;
System.out.print("\n Output :\n");
System.out.print(n3 + "/" + n4 + "\n\n" );
System.exit(0);
}
}
Interesting question. Here's some executable code that does it with minimal code:
/** #return the greatest common denominator */
public static long gcd(long a, long b) {
return b == 0 ? a : gcd(b, a % b);
}
public static String asFraction(long a, long b) {
long gcd = gcd(a, b);
return (a / gcd) + "/" + (b / gcd);
}
// Some tests
public static void main(String[] args) {
System.out.println(asFraction(500, 1000)); // "1/2"
System.out.println(asFraction(17, 3)); // "17/3"
System.out.println(asFraction(462, 1071)); // "22/51"
}
Bonus methods:
/** #return the lowest common multiple */
public static long lcm(long a, long b) {
return a * b / gcd(a, b);
}
/** #return the greatest common denominator */
public static long gcd(List<? extends Number> numbers) {
return numbers.stream().map(Number::longValue).reduce((a, b) -> gcd(a, b)).orElseThrow(NoSuchElementException::new);
}
/** #return the lowest common multiple */
public static long lcm(List<? extends Number> numbers) {
return numbers.stream().map(Number::longValue).reduce((a, b) -> lcm(a, b)).orElseThrow(NoSuchElementException::new);
}
You need the GCD. Either use BigInteger like Nathan mentioned or if you can't, use your own.
public int GCD(int a, int b){
if (b==0) return a;
return GCD(b,a%b);
}
Then you can divide each number by the GCD, like you have done above.
This will give you an improper fraction. If you need a mixed fraction then you can get the new numbers. Example if you had 1500 and 500 for inputs you would end up with 3/2 as your answer. Maybe you want 1 1/2. So you just divide 3/2 and get 1 and then get the remainder of 3/2 which is also 1. The denominator will stay the same.
whole = x/y;
numerator x%y;
denominator = y;
In case you don't believe me that this works, you can check out
http://en.wikipedia.org/wiki/Euclidean_algorithm
I just happen to like the recursive function because it's clean and simple.
Your algorithm is close, but not exactly correct. Also, you should probably create a new function if you want to find the gcd. Just makes it a little cleaner and easier to read. You can also test that function as well.
For reference, what you implemented is the original subtractive Euclidean Algorithm to calculate the greatest common divisor of two numbers.
A lot faster version is using the remainder from integer division, e.g. % instead of - in your loop:
while (n1 != 0 && n2 != 0){
if(n1 > n2)
n1 = n1 % n2;
else
n2 = n2 % n1;
}
... and then make sure you will use the one which is not zero.
A more streamlined version would be this:
while(n1 != 0) {
int old_n1 = n1;
n1 = n2 % n1;
n2 = old_n1;
}
and then use n1. Matt's answer shows a recursive version of the same algorithm.
You should make this class something other than a container for static methods. Here is a skeleton
import java.math.BigInteger;
public class BigRational
{
private BigInteger num;
private BigInteger denom;
public BigRational(BigInteger _num, BigInteger _denom)
{
//put the negative on top
// reduce BigRational using the BigInteger gcd method
}
public BigRational()
{
this(BigInteger.ZERO, BigInteger.ONE);
}
public BigRational add(BigRational that)
{
// return this + that;
}
.
.
.
//etc
}
}
I have a similar BigRational class I use. The GcdFunction is makes use of BigInteger's gcd function:
public class GcdFunction implements BinaryFunction {
#Override
public BigRational apply(final BigRational left, final BigRational right) {
if (!(left.isInteger() && right.isInteger())) {
throw new EvaluationException("GCD can only be applied to integers");
}
return new BigRational(left.getNumerator().gcd((right.getNumerator())));
}
}
BigRational contains a BigInteger numerator and denominator. isInteger() returns true if the simplified ratio's denominator is equal to 1.
Noticed that all answers here do not mention the iterative implementation of the Euclidean algorithm.
public static long gcdLongIterative(long a, long b) {
long tmp;
while (0 != b) {
tmp = b;
b = a % b;
a = tmp;
}
return a;
}
I implemented the validation test like #Bohemian and both recursive and iterative implementations work the same, however the iterative approach is faster. The benchmarks show small improvement, but it's improvement and overall it feels better to not use the stack so much and depend fully on the Java VM to optimize its implementation depend. Even if the benchmarks would be the same I would still feel better with the iterative as that would be more portable while the recursive was only optimized by my host Java, but might not be so well optimized on other's VMs.
Benchmark results (code is on the bottom of the answer):
(100 000 000 iterations)
gcd recursive: 3113ms
gcd iterative: 3079ms
gcd BigInteger: 13672ms
Signs:
One difference I noticed (besides the performance) is that the signs are handled differently, hand implemented Euclidean algorithm gcdLong and my gcdLongIterative behave the same, but both are different from BigInteger which tends to 'keep' the signs as they are. It seems that in essence the gcd and gcdLongIterative can return a negative number, while BigInteger will return positive only.
gcdLong and gcdLongIterative implementations:
-4/-2 => 2/1
-10/200 => 1/-20
10/-200 => 1/-20
BigInteger implementation tends to 'keep' the signs:
-4/-2 => -2/-1
-10/200 => -1/20
10/-200 => 1/-20
All results when used for fractions are valid, but it's worth considering post-process normalization if you expect the numbers in a specific 'style'.
For example, if the BigInteger behavior is preferred, then just returning absolute value should be enough, like here:
public static long gcdLongIterative(long a, long b) {
long tmp;
while (0 != b) {
tmp = b;
b = a % b;
a = tmp;
}
return Math.abs(a);
}
Performance:
Inspired by #Xabster benchmark (from Java: Get Greatest Common Divisor, which method is better?) I extended it to test all 3 implementations, in some cases both recursive and iterative were performing the same, however the iterative is slightly faster in most of the cases.
The benchmark code:
import java.math.BigInteger;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
public class Test {
private static final int BENCHMARK_ITERATIONS = 100000000;
public static long gcdLong(long a, long b) {
return b == 0 ? a : gcdLong(b, a % b);
}
public static long gcdLongIterative(long a, long b) {
long tmp;
while (0 != b) {
tmp = b;
b = a % b;
a = tmp;
}
return a;
}
public static long gcdLongBigInteger(long a, long b) {
return BigInteger.valueOf(a).gcd(BigInteger.valueOf((b))).longValue();
}
public static String asFractionGcdLong(long a, long b) {
long gcd = gcdLong(a, b);
return (a / gcd) + "/" + (b / gcd);
}
public static String asFractionGcdLongIterative(long a, long b) {
long gcd = gcdLongIterative(a, b);
return (a / gcd) + "/" + (b / gcd);
}
public static String asFractionGcdLongBI(long a, long b) {
long gcd = gcdLongBigInteger(a, b);
return (a / gcd) + "/" + (b / gcd);
}
public static void test(String actual, String expected) {
boolean match = expected.equals(actual);
if (match) {
System.out.println("Actual and expected match=" + expected);
} else {
System.out.println("NO match expected=" + expected + " actual=" + actual);
}
}
public static class Values {
public long a;
public long b;
public String expected;
public Values(long a, long b, String expected) {
this.a = a;
this.b = b;
this.expected = expected;
}
}
public static void validityTest() {
List<Values> vals = new LinkedList<Values>(Arrays.asList(
new Values(500, 1000, "1/2"),
new Values(17, 3, "17/3"),
new Values(462, 1071, "22/51"),
new Values(-4, -2, "2/1"),
new Values(-10, 200, "1/-20"),
new Values(10, -200, "1/-20")
));
System.out.println("------ Recursive implementation -------");
vals.forEach(v -> test(asFractionGcdLong(v.a, v.b), v.expected));
System.out.println();
System.out.println("------ Iterative implementation -------");
vals.forEach(v -> test(asFractionGcdLongIterative(v.a, v.b), v.expected));
System.out.println();
System.out.println("------ BigInteger implementation -------");
vals.forEach(v -> test(asFractionGcdLongBI(v.a, v.b), v.expected));
System.out.println();
}
public static void benchMark() {
Random r = new Random();
long[] nums = new long[BENCHMARK_ITERATIONS];
for (int i = 0 ; i < nums.length ; i++) nums[i] = r.nextLong();
System.out.println("Waming up for benchmark...");
for (int i = 0 ; i < nums.length-1; i++) gcdLong(i, i + 1);
for (int i = 0 ; i < nums.length-1; i++) gcdLongIterative(i, i + 1);
for (int i = 0 ; i < nums.length-1; i++) gcdLongBigInteger(i, i + 1);
System.out.println("Started benchmark...");
long s = System.currentTimeMillis();
for (int i = 0 ; i < nums.length-1; i++) gcdLong(i, i + 1);
System.out.println("recursive: " + (System.currentTimeMillis() - s) + "ms");
s = System.currentTimeMillis();
for (int i = 0 ; i < nums.length-1; i++) gcdLongIterative(i, i + 1);
System.out.println("iterative: " + (System.currentTimeMillis() - s) + "ms");
s = System.currentTimeMillis();
for (int i = 0 ; i < nums.length-1; i++) gcdLongBigInteger(i, i + 1);
System.out.println("BigInteger: " + (System.currentTimeMillis() - s) + "ms");
}
public static void main(String[] args) {
validityTest();
benchMark();
}
}
Who wants to help me with my homework?
I'm try to implement Fermat's primality test in Java using BigIntegers. My implementation is as follows, but unfortunately it doesn't work. Any ideas?
public static boolean checkPrime(BigInteger n, int maxIterations)
{
if (n.equals(BigInteger.ONE))
return false;
BigInteger a;
Random rand = new Random();
for (int i = 0; i < maxIterations; i++)
{
a = new BigInteger(n.bitLength() - 1, rand);
a = a.modPow(n.subtract(BigInteger.ONE), n);
if (!a.equals(BigInteger.ONE))
return false;
}
return true;
}
I'm new to BigIntegers.
Thanks!
Your use of the particular BigInteger constructor is reasonable, but you should use a rejection method to select a fermat base a. Here is a slight modification of your method in a class which also uses exactly one Random object:
import java.math.BigInteger;
import java.util.Random;
public class FermatTestExample
{
private final static Random rand = new Random();
private static BigInteger getRandomFermatBase(BigInteger n)
{
// Rejection method: ask for a random integer but reject it if it isn't
// in the acceptable set.
while (true)
{
final BigInteger a = new BigInteger (n.bitLength(), rand);
// must have 1 <= a < n
if (BigInteger.ONE.compareTo(a) <= 0 && a.compareTo(n) < 0)
{
return a;
}
}
}
public static boolean checkPrime(BigInteger n, int maxIterations)
{
if (n.equals(BigInteger.ONE))
return false;
for (int i = 0; i < maxIterations; i++)
{
BigInteger a = getRandomFermatBase(n);
a = a.modPow(n.subtract(BigInteger.ONE), n);
if (!a.equals(BigInteger.ONE))
return false;
}
return true;
}
public static void main(String[] args)
{
System.out.printf("checkprime(2) is %b%n", checkPrime(BigInteger.valueOf(2L), 20));
System.out.printf("checkprime(5) is %b%n", checkPrime(BigInteger.valueOf(5L), 20));
System.out.printf("checkprime(7) is %b%n", checkPrime(BigInteger.valueOf(7L), 20));
System.out.printf("checkprime(9) is %b%n", checkPrime(BigInteger.valueOf(9L), 20));
}
}
a should be "pick a randomly in the range (1, n − 1]" and I don't really see that happening. You could print a to check that.
As for how to do that:
BigInteger a = BigInteger.valueOf(random.nextInt(n-2)+2);
e.g. You shouldn't use the BigInteger constructor with a Random argument; that's just a source of randomness, but a should be a random value.
The 'random.nextInt(n-1)+1' comes from the definition of nextInt which, given argument k, returns a random value 0 up to and including k-1. And you want a to be larger than 1 and smaller than n.