public static BigInteger OtherToDecimal(String value, int base) {
BigInteger sum = new BigInteger("0");
String kt = "0123456789ABCDEF";//
for (int i = 0; i < value.length(); i++) {
BigInteger k = BigDecimal.valueOf(pow(base, value.length() - 1 - i)).toBigInteger();
sum = sum.add((BigInteger.valueOf(kt.indexOf(value.charAt(i))).multiply(k)));
}
return sum;
}
when i test this function with base16 :F0F0F0F0F0F0F0, it return right result = 67818912035696880
BUT when i test with base16: F0F0F0F0F0F0F0F0, it returns wrong result: 17361641481138401580 which right result must be 17361641481138401520
please help me!
Math.pow delivers a double, 8 bytes. So from some huge double value, it becomes imprecise in the less significant digits.
You could have used
new BigInteger(value, base)
The repair is:
BigInteger k = BigDecimal.valueOf(base).pow(value.length() - 1 - i));
Related
Want to replace BigInteger loop in Java Stream API.
Below code, I have to modify in java8 using Stream API. Because of performance concerns.
My question what would be the best practice to change below code into best performance.
public BigInteger getSum(BigInteger n, BigInteger c) {
BigInteger sum = BigInteger.ZERO;
for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i=i.add(BigInteger.ONE)) {
sum = sum.add(calculateProduct(i, i.subtract(BigInteger.ONE), c));
}
return sum;
}
private BigInteger calculateProduct(BigInteger i, BigInteger j, BigInteger c) {
if (j.compareTo(BigInteger.ZERO) < 0) return BigInteger.ZERO;
if (j.compareTo(BigInteger.ZERO) == 0) return BigInteger.ONE;
if ((i.subtract(j).compareTo(c)) <= 0){
return j.add(BigInteger.ONE).multiply(calculateProduct(i, j.subtract(BigInteger.ONE), c));
}else
return BigInteger.ONE;
}
It looks like you are adding up products of sliding window of width c. If you want to improve performance, get rid of recursion and avoid recomputing the entire product. Use the product computed in the previous step: multiply it by the number entering the window and divide by the number exiting the window. Division is slower but it will pay off for larger values of c.
Finally, while I will keep your method signature, you really only need BigInteger as return.
BigInteger getSum(BigInteger n, BigInteger c) {
BigInteger p = BigInteger.ONE, sum = BigInteger.ZERO;
for (BigInteger x = BigInteger.ONE; x.compareTo(n) < 0; x = x.add(BigInteger.ONE)) {
p = p.multiply(x);
if (x.compareTo(c) > 0) {
p = p.divide(x.subtract(c));
}
sum = sum.add(p);
}
return sum;
}
If you want to speed it up further, you can use a bit of math to avoid having to divide at every step. Your sum can be broken up into s1 = sum[1,c) x! and s2 = sum[c,n) x!/(x-c)!. The second sum equals n!/(n-c-1)!/(c+1) (follows from hockey stick identity). The method below does not handle the trivial case of c >=n. I will leave that to you.
private static BigInteger fasterSum(BigInteger n, BigInteger c) {
assert c.compareTo(n) < 0;
BigInteger sum = ZERO, p = ONE;
for (BigInteger x = ONE; x.compareTo(c) < 0; x = x.add(ONE)) {
p = p.multiply(x);
sum = sum.add(p);
}
// sum[c,n) x!/(x-c)! = n!/(n-c-1)!/(c+1)
p = ONE;
for (BigInteger x = n.subtract(c); x.compareTo(n) <= 0; x = x.add(ONE)) {
p = p.multiply(x);
}
sum = sum.add(p.divide(c.add(ONE)));
return sum;
}
So I assume you want to add a list of BigInteger:
You can do that by using a reduce operation (https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html)
List<BigInteger> list = new ArrayList<>();
list.add(BigInteger.valueOf(5));
list.add(BigInteger.valueOf(1));
list.add(BigInteger.valueOf(3));
list.add(BigInteger.valueOf(10));
list.add(BigInteger.valueOf(2));
BigInteger sum = list.stream().reduce((x, y) -> x.add(y)).get();
System.out.println(sum);
That will calculate the sum, an equivalent would be:
BigInteger sum = list.stream().reduce(BigInteger::add).get();
You could also write an own Collector that is reusable and extract the reduce operation to there:
public static Collector<BigInteger, ?, BigInteger> calculateSum() {
return Collectors.reducing(BigInteger.ZERO, BigInteger::add);
}
and then do:
BigInteger sum = list.stream().collect(calculateSum());
I want to compute the answer of C(n,k),such as C(10,2)=10*9/2*1 = 45
If I test my code by small numbers like 10, the code works.
However, when I try to compute C(1000,900), it compiles
Exception in thread "main" java.lang.ArithmeticException: / by zero
I've seen someone says it should use BigInteger,But after I tried, it still has errors.
For example: I change int factorial into BigInteger factorial,
while the for loop in cSelect, I can not change int i into BigInteger type,
As result, the answer up/factorial(y) has errors.
Please help me to fix this problem. Thanks!!
public class Test {
// Write a factorial function
static int factorial(int m) {
int result =1;
for (int i=2; i<=m; i++) {
result = result*i;
}
return result;
}
// Caculate C(x,y)
static int cSelect(int x, int y) {
int up=1;
for(int i=x; i>=(x-y+1); i--) {
up = up*i;
}
return up/factorial(y);
}
public static void main(String[] args) {
System.out.println(cSelect(1000,900));
}
}
Your code is fairly easy to translate in factorial. Start with ONE, multiply by the BigInteger.valueOf(long) for each i in your loop. Like,
// Write a factorial function
static BigInteger factorial(int m) {
BigInteger result = BigInteger.ONE;
for (int i = 2; i <= m; i++) {
result = result.multiply(BigInteger.valueOf(i));
}
return result;
}
Your other function does exactly the same, plus a division by the result of factorial(y). Like,
// Caculate C(x,y)
static BigInteger cSelect(int x, int y) {
BigInteger up = BigInteger.ONE;
for (int i = x; i >= (x - y + 1); i--) {
up = up.multiply(BigInteger.valueOf(i));
}
return up.divide(factorial(y));
}
With no other changes I get
63850511926305130236698511142022274281262900693853331776286816221524376994750901948920974351797699894319420811933446197797592213357065053890
Which I assume is correct.
First, return value must be BigInteger, because result of C(1000,900) far exceeds the range on an int.
Second, you don't need separate factorial() method. Doing the division as you iterate will improve memory footprint by not creating excessively large intermediate values (at cost of doing multiple divisions, but even so it might actually be faster).
Like this:
static BigInteger cSelect(int x, int y) {
BigInteger v = BigInteger.ONE;
for (int i = x, j = 1; j <= y; i--, j++)
v = v.multiply(BigInteger.valueOf(i)).divide(BigInteger.valueOf(j));
return v;
}
By counting i down and j up, there will never be a fraction from the division.
Test
System.out.println(cSelect(10, 2));
System.out.println(cSelect(1000, 900));
Output
45
63850511926305130236698511142022274281262900693853331776286816221524376994750901948920974351797699894319420811933446197797592213357065053890
You have to use BigInteger to do the calculation.
The value you are trying to compute is approximately 6.385051192630516e+139 and it is not representable as a Java primitive integer value.
Even if the result was representable, the reason you are getting divide by zero errors is that the divisor expression 900! ∗ 100! is overflowing to zero. You then divide by that zero.
The reason that it overflows to zero is that it is divisible by 2^32 and 2^64. That can be proven by using some simple algebra to compute the number of factors of 2 there are in 900! and 100!
There should be a program, which square every digit of an integer and after that concatenate these temporary numbers into a new integer.
I have written a code, which do the trick regarding to my test cases, but an automated tester gives errors for some random generated input numbers.
public class SquareDigit {
public int squareDigits(int n) {
int tmp = 0;
String returnvalue="";
while(n > 0) {
tmp = n % 10;
tmp = tmp * tmp;
returnvalue = returnvalue + Integer.toString(tmp);
n /= 10;
}
int result=Integer.parseInt(returnvalue);
return result;
}
}
Use BigInteger.
A BigInteger is a class that hold integer with arbitrary precision:
Immutable arbitrary-precision integers.
Your code become wrong when squaring a number you go over the maximum available range of type int. A long can solve the problem if you test on a range that is under the long range. A BigInteger work for any integer number.
Code should be something similar to that:
public BigInteger squareDigits(int n) {
BigInteger tmp = null;
String returnvalue = "";
while (n > 0) {
tmp = BigInteger.valueOf(n % 10);
tmp = tmp.pow(2);
returnvalue = returnvalue + String.valueOf(tmp);
n /= 10;
}
return new BigInteger(returnvalue);
}
...
System.out.println(squareDigits(123456789)); // Print 816449362516941
Use
returnvalue = Integer.toString(tmp) + returnvalue;
instead of
returnvalue = returnvalue + Integer.toString(tmp);
You iterate the digits from back to front so e.g for input 123 the intermediate results should be
"9"
"49"
"149"
but in your code it's
"9"
"94"
"941"
public long bin_to_dec() {
int leng = a.length();
for (int i = 0, j = (leng - 1); i < leng; i++, j--) {
int number = Character.getNumericValue(a.charAt(j));
result = result + (number * ((long) Math.pow(2, i)));
}
return result;
}
This code takes a binary string as argument and return it's decimal value .
but for a long string i.e.
(111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111)
it returns -28 .
Why is the memory out of range?
or is my code is incorrect?
You are probably overrunning the length of an int. Integers in java are 32 bit and that binary string is 91 bits.
Try using something like BigInteger instead, which will not overflow. In fact, BigInteger has a built-in method for this:
BigInteger result = new BigInteger(a, 2);
I found out longs wont cut it, as the numbers I'm calculating are to huge to fit. I'm struggling with the concept of BigInts.
Lets say I have the following equation to perform.
int p = 11549
int n = 252817
The equation is as follows.. : ( number * p )^ (to the power of i)%n .
With longs I just did :
long number;
long p;
long n;
long temp;
long total;
for (int i=0; i<6;i++) {
temp = numer*Math.pow(p,i);
total += temp;
}
total %= n;
But when i use Math.pow on I the numbers get to huge to use this method, and I need to use BigIntegers. I Just dont understand how I can do it. Right now I got this : (Missing the % until i can figure out the power off statement.)
long temp;
long p;
BigInteger opphoyd;
BigInteger mod;
for (int i=0;i<6;i++) {
temp = number * p;
opphoyd = BigInteger.valueOf(temp);
mod = BigInteger.valueOf(i);
mod.add(opphoyd.pow(i));
mod.add(opphoyd);
System.out.println(mod);
}
But its not working at all, could anyone point me in the right direction?
BigInteger's add method (and most of the other methods) does not modify the BigInteger it is called on. Instead it returns a new BigInteger.
So you would need to do:
BigInteger sum = mod.add(opphoyd);
Take a look at the javadocs, it will be very helpful when working with BigInteger.
long temp;
long p;
BigInteger opphoyd;
BigInteger mod;
for( int i = 0; i < 6; i++ ) {
temp = number * p;
opphoyd = BigInteger.valueOf(temp);
mod = BigInteger.valueOf(i);
BigInteger sum = mod.add( opphoyd.pow(i));
sum = sum.add(opphoyd);
System.out.println( sum );
}