Total value of sum of integers does not equal calculated value - java

While doing unsigned int conversions in Java I got some "anomalous" results, which I have cut down to the minimal case shown below. The same code in C generates similar results.
The problem is that when I calculate the theoretical sum of the absolute value of all integer values using the Gauss summation formula n(n+1)/2 (see https://en.wikipedia.org/wiki/Summation) the value I calculate does not match the total if I actually add up all the absolute values one by one.
Note that when I calculate the total using the summation formula the division by 2 "/2" is omitted because I am adding both the negative and positive numbers as absolute values, and at the end I have to add (longIntegerMax + 1) because the negative numbers have one extra number at the end (Integer.MIN) which has the absolute value of Integer.MAX + 1.
public static void main( String[] asArguments ){
long longAbsoluteTotal = 0;
long longNumberOfIntegers = 0;
long longIntegerMax = Integer.MAX_VALUE;
long longIntegerMin = Integer.MIN_VALUE;
for( int i = Integer.MIN_VALUE;; i++ ){
longNumberOfIntegers++;
if( i < 0 ){
longAbsoluteTotal += i * -1;
} else {
longAbsoluteTotal += i;
}
if( i == Integer.MAX_VALUE ) break;
}
long longCalculatedTotal = longIntegerMax * (longIntegerMax + 1) + longIntegerMax + 1;
System.out.println( "count of all integers: " + longNumberOfIntegers );
System.out.println( "total of absolute value of all integers: " + longAbsoluteTotal );
System.out.println( "calculated total of absolute value of all integers: " + longCalculatedTotal );
}
output:
count of all integers: 4294967296
total of absolute value of all integers: 4611686014132420608
calculated total of absolute value of all integers: 4611686018427387904
As you can see, the calculated total is close to the real total, but does not match it exactly. Why not?

The problem is here ..
longAbsoluteTotal += i * -1;
The ( i * -1 ) is still integer arithmetic, it produces a number greater than Integer.MAX_VALUE and overflows back to Integer.MIN_VALUE;
You could fix this as #Evgeniy suggested, or you could use
longAbsoluteTotal += i * -1L;
to force long arithmetic.

4611686014132420608 - 4611686018427387904 = -4294967296 = Integer.MIN_VALUE * 2
The reason is that
Integer.MIN_VALUE * -1 == Integer.MIN_VALUE
Since we use two's complement to represent negative value.
The two's complement of Integer.MIN_VALUE(0x80000000) = 0x7fffffff + 0x1 = 0x80000000.

Change
for( int i = Integer.MIN_VALUE;; i++ ){
to
for( long i = Integer.MIN_VALUE;; i++ ){
all will be OK
It's similar to -Integer.MIN_VALUE == -2147483648

Related

Starting from 1 how far can I count, when I can use any digit a maximum of N times

My problem is as follows; for number N, I need to find out what is the largest value I can count to, when each digit can be used N times.
For example if N = 5, the largest value is 12, since at that point the digit 1 has been used 5 times.
My original approach was to simply iterate through all numbers and keep a tally of how many times each digit has been used so far. This is obviously very inefficient when N is large, so am looking for advice on what would be a smarter (and more efficient) way to achieve this.
public class Counter {
private static Hashtable<Integer, Integer> numbers;
public static void main(String[] args){
Counter c = new Counter();
c.run(9);
}
public Counter() {
numbers = new Hashtable<Integer, Integer>();
numbers.put(0, 0);
numbers.put(1, 0);
numbers.put(2, 0);
numbers.put(3, 0);
numbers.put(4, 0);
numbers.put(5, 0);
numbers.put(6, 0);
numbers.put(7, 0);
numbers.put(8, 0);
numbers.put(9, 0);
}
public static void run(int maxRepeat) {
int keeper = 0;
for(int maxFound = 0; maxFound <= maxRepeat; maxFound++) {
keeper++;
for (int i = 0; i < Integer.toString(keeper).length(); i++) {
int a = Integer.toString(keeper).charAt(i);
//here update the tally for appropriate digit and check if max repeats is reached
}
}
System.out.println(keeper);
}
}
For starters, rather than backing your Counter with a Hashtable, use an int[] instead. When you know exactly how many elements your map has to have, and especially when the keys are numbers, an array is perfect.
That being said, I think the most effective speedup is likely to come from better math, not better algorithms. With some experimentation (or it may be obvious), you'll notice that 1 is always the first digit to be used a given number of times. So given N, if you can find which number is the first to use the digit 1 N+1 times, you know your answer is the number right before that. This would let you solve the problem without actually having to count that high.
Now, let's look at how many 1's are used counting up to various numbers. Throughout this post I will use n to designate a number when we are trying to figure out how many 1's are used to count up to a number, whereas capital N designates how many 1's are used to count up to something.
One digit numbers
Starting with the single-digit numbers:
1: 1
2: 1
...
9: 1
Clearly the number of 1's required to count up to a one-digit number is... 1. Well, actually we forgot one:
0: 0
That will be important later. So we should say this: the number of 1's required to count up to a one-digit number X is X > 0 ? 1 : 0. Let's define a mathematical function f(n) that will represent "number of 1's required to count up to n". Then
f(X) = X > 0 ? 1 : 0
Two-digit numbers
For two-digit numbers, there are two types. For numbers of the form 1X,
10: 2
11: 4
12: 5
...
19: 12
You can think of it like this: counting up to 1X requires a number of 1's equal to
f(9) (from counting up to 9) plus
1 (from 10) plus
X (from the first digits of 11-1X inclusive, if X > 0) plus
however many 1's were required to count up to X
Or mathematically,
f(1X) = f(9) + 1 + X + f(X)
Then there are the two-digit numbers higher than 19:
21: 13
31: 14
...
91: 20
The number of 1's required to count to a two-digit number YX with Y > 1 is
f(19) (from counting up to 19) plus
f(9) * (Y - 2) (from the 1's in numbers 20 through (Y-1)9 inclusive - like if Y = 5, I mean the 1's in 20-49, which come from 21, 31, 41) plus
however many 1's were required to count up to X
Or mathematically, for Y > 1,
f(YX) = f(19) + f(9) * (Y - 2) + f(X)
= f(9) + 1 + 9 + f(9) + f(9) * (Y - 2) + f(X)
= 10 + f(9) * Y + f(X)
Three-digit numbers
Once you get into three-digit numbers, you can kind of extend the pattern. For any three-digit number of the form 1YX (and now Y can be anything), the total count of 1's from counting up to that number will be
f(99) (from counting up to 99) plus
1 (from 100) plus
10 * Y + X (from the first digits of 101-1YX inclusive) plus
however many 1's were required to count up to YX in two-digit numbers
so
f(1YX) = f(99) + 1 + YX + f(YX)
Note the parallel to f(1X). Continuing the logic to more digits, the pattern, for numbers which start with 1, is
f(1[m-digits]) = f(10^m - 1) + 1 + [m-digits] + f([m-digits])
with [m-digits] representing a sequence of digits of length m.
Now, for three-digit numbers ZYX that don't start with 1, i.e. Z > 1, the number of 1's required to count up to them is
f(199) (from counting up to 199) plus
f(99) * (Z - 2) (from the 1's in 200-(Z-1)99 inclusive) plus
however many 1's were required to count up to YX
so
f(ZYX) = f(199) + f(99) * (Z - 2) + f(YX)
= f(99) + 1 + 99 + f(99) + f(99) * (Z - 2) + f(YX)
= 100 + f(99) * Z + f(YX)
And the pattern for numbers that don't start with 1 now seems to be clear:
f(Z[m-digits]) = 10^m + f(10^m - 1) * Z + f([m-digits])
General case
We can combine the last result with the formula for numbers that do start with 1. You should be able to verify that the following formula is equivalent to the appropriate case given above for all digits Z 1-9, and that it does the right thing when Z == 0:
f(Z[m-digits]) = f(10^m - 1) * Z + f([m-digits])
+ (Z > 1) ? 10^m : Z * ([m-digits] + 1)
And for numbers of the form 10^m - 1, like 99, 999, etc. you can directly evaluate the function:
f(10^m - 1) = m * 10^(m-1)
because the digit 1 is going to be used 10^(m-1) times in each of the m digits - for example, when counting up to 999, there will be 100 1's used in the hundreds' place, 100 1's used in the tens' place, and 100 1's used in the ones' place. So this becomes
f(Z[m-digits]) = Z * m * 10^(m-1) + f([m-digits])
+ (Z > 1) ? 10^m : Z * ([m-digits] + 1)
You can tinker with the exact expression, but I think this is pretty close to as good as it gets, for this particular approach anyway. What you have here is a recursion relation that allows you to evaluate f(n), the number of 1's required to count up to n, by stripping off a leading digit at each step. Its time complexity is logarithmic in n.
Implementation
Implementing this function is straightforward given the last formula above. You can technically get away with one base case in the recursion: the empty string, i.e. define f("") to be 0. But it will save you a few calls to also handle single digits as well as numbers of the form 10^m - 1. Here's how I'd do it, omitting a bit of argument validation:
private static Pattern nines = Pattern.compile("9+");
/** Return 10^m for m=0,1,...,18 */
private long pow10(int m) {
// implement with either pow(10, m) or a switch statement
}
public long f(String n) {
int Z = Integer.parseInt(n.substring(0, 1));
int nlen = n.length();
if (nlen == 1) {
return Z > 0 ? 1 : 0;
}
if (nines.matcher(n).matches()) {
return nlen * pow10(nlen - 1);
}
String m_digits = n.substring(1);
int m = nlen - 1;
return Z * m * pow10(m - 1) + f_impl(m_digits)
+ (Z > 1 ? pow10(m) : Z * (Long.parseLong(m_digits) + 1));
}
Inverting
This algorithm solves the inverse of the the question you're asking: that is, it figures out how many times a digit is used counting up to n, whereas you want to know which n you can reach with a given number N of digits (i.e. 1's). So, as I mentioned back in the beginning, you're looking for the first n for which f(n+1) > N.
The most straightforward way to do this is to just start counting up from n = 0 and see when you exceed N.
public long howHigh(long N) {
long n = 0;
while (f(n+1) <= N) { n++; }
return n;
}
But of course that's no better (actually probably worse) than accumulating counts in an array. The whole point of having f is that you don't have to test every number; you can jump up by large intervals until you find an n such that f(n+1) > N, and then narrow down your search using the jumps. A reasonably simple method I'd recommend is exponential search to put an upper bound on the result, followed by a binary search to narrow it down:
public long howHigh(long N) {
long upper = 1;
while (f(upper + 1) <= N) {
upper *= 2;
}
long lower = upper / 2, mid = -1;
while (lower < upper) {
mid = (lower + upper) / 2;
if (f(mid + 1) > N) {
upper = mid;
}
else {
lower = mid + 1;
}
}
return lower;
}
Since the implementation of f from above is O(log(n)) and exponential+binary search is also O(log(n)), the final algorithm should be something like O(log^2(n)), and I think the relation between N and n is linear enough that you could consider it O(log^2(N)) too. If you search in log space and judiciously cache computed values of the function, it might be possible to bring it down to roughly O(log(N)). A variant that might provide a significant speedup is sticking in a round of interpolation search after determining the upper bound, but that's tricky to code properly. Fully optimizing the search algorithm is probably a matter for another question though.
This should be more efficient. Use integer array of size 10 to keep the count of digits.
public static int getMaxNumber(int N) {
int[] counts = new int[10];
int number = 0;
boolean limitReached = false;
while (!limitReached) {
number++;
char[] digits = Integer.toString(number).toCharArray();
for (char digit : digits) {
int count = counts[digit - '0'];
count++;
counts[digit - '0'] = count;
if (count >= N) {
limitReached = true;
}
}
}
return number;
}
UPDATE 1: As #Modus Tollens mentioned initial code has a bug. When N = 3 it returns 11, but there are four 1s between 1 and 11. The fix is to check if limit is breached count[i] > N on given number, previous number should be return. But if for some i count[i] == N for other j count[j] <= N, the actual number should be returned.
Please see corresponding code below:
public static int getMaxNumber(int N) {
int[] counts = new int[10];
int number = 0;
while (true) {
number++;
char[] digits = Integer.toString(number).toCharArray();
boolean limitReached = false;
for (char digit : digits) {
int count = counts[digit - '0'];
count++;
counts[digit - '0'] = count;
if (count == N) {
//we should break loop if some count[i] equals to N
limitReached = true;
} else if (count > N) {
//previous number should be returned immediately
//, if current number gives more unique digits than N
return number - 1;
}
}
if (limitReached) {
return number;
}
}
}
UPDATE 2: As #David Z and #Modus Tollens mentioned, in case if N=13, 30 should be returned, ie, algo stops when N is breached but not reached. If this is initial requirement, the code will be even simpler:
public static int getMaxNumber(int N) {
int[] counts = new int[10];
int number = 0;
while (true) {
number++;
char[] digits = Integer.toString(number).toCharArray();
for (char digit : digits) {
int count = counts[digit - '0'];
count++;
counts[digit - '0'] = count;
if (count > N) {
return number - 1;
}
}
}
}

The method returns true if the integer is divisible by 3 and returns false if the integer is not divisible by 3

This is what I have so far; I have to use this main method.
public class HW4 {
public static boolean isDivisibleByThree(String n) {
int sum = 0;
int value;
for (int k = 0; k < n.length(); k++) {
char ch = n.charAt(k);
value = Character.getNumericValue(ch);
sum = sum*value;
}
return sum*3 == 0;
}
}
It always comes out true and I'm really stuck in this part. So if you can, can you help me out?
A sum is a cumulative addition (not multiplication).
Change this line:
sum = sum * value;
To
sum = sum + value;
Or the more brief version:
sum += value;
Much easier solution: use the mod-function:
int number = int.Parse(input);
bool result = (number % 3 == 0);
Two things:
sum = sum * value? This should probably be sum = sum + value, or short sum += value
sum * 3 == 0 should probably be sum % 3 == 0
If you are required to not use the % operator, you could alternatively do:
double check = (double)sum / 3.0;
return check == (int)check;
The problem with negative numbers is that the - gets parsed too, you could sove it by dropping it:
if (n[0] == '-') {
n = n.substring(1);
}
This drops the sign if it is negative and does nothing otherwise.
Unless I'm missing something, you would first use Integer.parseInt(String) to parse the int from the String. Then you can divide that value by 3 using integer division. Finally, test if that number multiplied by 3 is the original value.
int value = Integer.parseInt(n);
int third = value / 3;
return (value == third * 3);

Doing a factorial with only one while loop

I'm trying to find the factorial of 9 down to 0, only using one while loop, but my idea isn't outputting a value.
I figured out the way to do it using two while loops:
int i;
count = 9;
while (count >= 0){
value = count;
i = count-1;
while (i > 0){
value = value * i;
i--;
}
System.out.print(value + ", ");
}
This worked but I've tried to change it to use only one while loop and got this:
int i;
for (count = 9; count < 0; count--){
value = count;
i = count-1;
while (i > 0){
value = value * i;
i--;
}
System.out.print(value + ", ");
}
I'm not completely sure if I'm using the for statement correctly but I think I am, or at least I think it should output something so I can debug it.
Could someone give me a hint in the right direction?
This will give you all the factorials from 9 down to 1 :
int i=1;
int value=1;
String res = "";
while (i <= 9){
value = value * i;
res = value + ((i>1)?",":"") + res;
i++;
}
System.out.print(res);
Output :
362880,40320,5040,720,120,24,6,2,1
Perhaps it's cheating, since I'm calculating the factorials in ascending order from 1! to 9!, but I'm reversing the order of the output in order to get the required result.
Edit :
If you also want 0! to be printed, a small change can do the trick :
int i=1;
int value=1;
String res = "";
while (i <= 10){
res = value + ((i>1)?",":"") + res;
value = value * i;
i++;
}
System.out.print(res);
Output :
362880,40320,5040,720,120,24,6,2,1,1
First, the reason why your second loop doesn't work is that you have the wrong condition in the for. The condition in the middle is one that will cause the loop to continue, not to stop. So what you were saying was "start from 9, and work while the number is less than 0". But of course, your number is greater than zero to begin with.
Second, I believe using a for loop is a little bit of cheating, because a for loop is just a specific case of while loop.
Now to the problem of the factorial itself. You know that a factorial n! is defined as (n-1)!*n.
The basic loop for calculating one specific factorial is:
int n = 5;
int factorial = 1;
while ( n > 0 ) {
factorial *= n;
n--;
}
System.out.println( "Factorial is: " + factorial );
This will give you the factorial of five. But it's not exactly based on the formula we are talking about. There is another way to calculate it, starting from 1:
int n = 5;
int factorial = 1;
int count = 1;
while ( count <= n ) {
factorial *= count;
count++;
}
System.out.println( "Factorial is " + factorial );
The interesting part about this way of doing it is that in every stage of the loop, factorial is actually the value (count-1)! and we are multiplying it by count. This is exactly the formula we were talking about.
And the good thing about it is that just before you did it, you had the value of the previous factorial. So if you printed it then, there you'd get a list of all the factorials along the way. So here is a modified loop that prints all the factorials.
int n = 9;
int factorial = 1;
int count = 0;
while ( count < n ) {
System.out.println( "Factorial of " + count + " is " + factorial );
count++;
factorial *= count;
}
System.out.println( "Factorial of " + n + " is " + factorial );
Note that I modified it a little more so that it will work with zero. The factorial of zero is a special case so we shouldn't multiply by zero - that will make all the factorials wrong. So I changed the loop to multiply only after I increase count to 1. But this also means that you have to print the final factorial out of the loop.
Just first assign value=i, then run your loop. You can get the factorial with only while loop.
Important: Because n!=n*(n-1)!, therefore, i-- should must be perform before value = value * i.
public static void main(String args[]) {
int value=5;
int i=value;
while (i > 1){
i--;
value = value * i;
}
System.out.print(value);
}
Update: If you want to count factorial of 0 to 9, then use this code: (It includes factorial of 0 also)
public static void main(String args[]){
int countLowest=0;
int countHighest=9;
int value=1;
while (countLowest<= countHighest){
if(countLowest==0)
value = value * (countLowest+1);
else
value=value*countLowest;
countLowest++;
System.out.println("Factorial of "+(countLowest-1)+" is "+value);
}
}
Result:
Factorial of 0 is 1
Factorial of 1 is 1
Factorial of 2 is 2
Factorial of 3 is 6
Factorial of 4 is 24
Factorial of 5 is 120
Factorial of 6 is 720
Factorial of 7 is 5040
Factorial of 8 is 40320
Factorial of 9 is 362880
count = 9;
sum=1;
while (count >= 1){
sum*=count;
--count;
}
System.out.print(sum);
it will give you 9!=362880

Make a number divisible by another number but with floats?

I have a random number that's suppose to fit into 360.0f. My problem is my function only works for ints. How would I make another number fit into another one evenly up or down (preferably closest)
How would I make this work with floats?
Here's what I've got:
public static float fitNumberEvenlyIntoAnother(int number, int numberToFitInto)
{
while(numberToFitInto % number != 0)
{
number += 1;
if(Math.abs(number / 2f) > Math.abs(numberToFitInto))
{
Log.w("fitNumberEvenlyIntoAnother", "Oh ow, the fitNumberEvenlyIntoAnother has surpassed the number it's suppose to fit into");
}
}
//This number needs to fit into the number evenly. Cannot be null or nan.
return number;
}
If you want to "adjust" a number x into a range r (e.g. an angle into [0,360[), then you could do the following:
double len = r.max - r.min;
double frac = x/len - Math.floor(x/len);
double result = frac < 0 ? r.min + len * (1 + frac) : r.min + len * frac;
What yo do is the following:
you get the size of the range as len (360 - 0 = 360 in the case of degrees)
you calculate len/(x % len)
if the fraction is negative you add 1
the result is the lower bound of the range plus the fraction (in range [0,1]) of the range's length
Instead of looping on the result, just test if the result of division is a whole number:
public static float fitNumberEvenlyIntoAnother(float number, float numberToFitInto) {
float result = numberToFitInto / number;
if (result == Math.round(result))
return result;
return Float.NaN;
}
You haven't indicated what should be returned if it doesn't fit evenly - this impl returns the not a number value - you may want to do something different.

Generating 10 digits unique random number in java

I am trying with below code to generate 10 digits unique random number. As per my req i have to create around 5000 unique numbers(ids). This is not working as expected. It also generates -ve numbers. Also sometimes one or two digits are missing in generated number resulting in 8 or 9 numbers not 10.
public static synchronized List generateRandomPin(){
int START =1000000000;
//int END = Integer.parseInt("9999999999");
//long END = Integer.parseInt("9999999999");
long END = 9999999999L;
Random random = new Random();
for (int idx = 1; idx <= 3000; ++idx){
createRandomInteger(START, END, random);
}
return null;
}
private static void createRandomInteger(int aStart, long aEnd, Random aRandom){
if ( aStart > aEnd ) {
throw new IllegalArgumentException("Start cannot exceed End.");
}
//get the range, casting to long to avoid overflow problems
long range = (long)aEnd - (long)aStart + 1;
logger.info("range>>>>>>>>>>>"+range);
// compute a fraction of the range, 0 <= frac < range
long fraction = (long)(range * aRandom.nextDouble());
logger.info("fraction>>>>>>>>>>>>>>>>>>>>"+fraction);
int randomNumber = (int)(fraction + aStart);
logger.info("Generated : " + randomNumber);
}
So you want a fixed length random number of 10 digits? This can be done easier:
long number = (long) Math.floor(Math.random() * 9_000_000_000L) + 1_000_000_000L;
Note that 10-digit numbers over Integer.MAX_VALUE doesn't fit in an int, hence the long.
I think the reason you're getting 8/9 digit values and negative numbers is that you're adding fraction, a long (signed 64-bit value) which may be larger than the positive int range (32-bit value) to aStart.
The value is overflowing such that randomNumber is in the negative 32-bit range or has almost wrapped around to aStart (since int is a signed 32-bit value, fraction would only need to be slightly less than (2^32 - aStart) for you to see 8 or 9 digit values).
You need to use long for all the values.
private static void createRandomInteger(int aStart, long aEnd, Random aRandom){
if ( aStart > aEnd ) {
throw new IllegalArgumentException("Start cannot exceed End.");
}
//get the range, casting to long to avoid overflow problems
long range = aEnd - (long)aStart + 1;
logger.info("range>>>>>>>>>>>"+range);
// compute a fraction of the range, 0 <= frac < range
long fraction = (long)(range * aRandom.nextDouble());
logger.info("fraction>>>>>>>>>>>>>>>>>>>>"+fraction);
long randomNumber = fraction + (long)aStart;
logger.info("Generated : " + randomNumber);
}
I don't know why noone realized that but I think the point is to generate "unique" random number which I am also trying to do that. I managed to generate 11 digits random number but I am not sure how to generate unique numbers. Also my approach is a little different. In this method I am appending number chars next to each other with for loop. Then returning long number.
public long generateID() {
Random rnd = new Random();
char [] digits = new char[11];
digits[0] = (char) (rnd.nextInt(9) + '1');
for(int i=1; i<digits.length; i++) {
digits[i] = (char) (rnd.nextInt(10) + '0');
}
return Long.parseLong(new String(digits));
}
I would use
long theRandomNum = (long) (Math.random()*Math.pow(10,10));
A general solution to return a 'n' digit number is
Math.floor(Math.random() * (9*Math.pow(10,n-1))) + Math.pow(10,(n-1))
For n=3, This would return numbers from 100 to 999 and so on.
You can even control the end range, i.e from 100 to 5xx but setting the "9" in the above equation "5" or any other number from 1-9
This is a utility method for generating a fixed length random number.
public final static String createRandomNumber(long len) {
if (len > 18)
throw new IllegalStateException("To many digits");
long tLen = (long) Math.pow(10, len - 1) * 9;
long number = (long) (Math.random() * tLen) + (long) Math.pow(10, len - 1) * 1;
String tVal = number + "";
if (tVal.length() != len) {
throw new IllegalStateException("The random number '" + tVal + "' is not '" + len + "' digits");
}
return tVal;
}
Maybe you are looking for this one:
Random rand = new Random();
long drand = (long)(rand.nextDouble()*10000000000L);
You can simply put this inside a loop.
this is for random number starting from 1 and 2 (10 digits).
public int gen() {
Random r = new Random(System.currentTimeMillis());
return 1000000000 + r.nextInt(2000000000);
}
hopefully it works.
Hi you can use the following method to generate 10 digit random number
private static int getRndNumber() {
Random random=new Random();
int randomNumber=0;
boolean loop=true;
while(loop) {
randomNumber=random.nextInt();
if(Integer.toString(randomNumber).length()==10 && !Integer.toString(randomNumber).startsWith("-")) {
loop=false;
}
}
return randomNumber;
}

Categories

Resources