Math explanation of why this code works - javascript

I encountered a problem in the site CodeFights that I resolved with two loops. While looking at other answer I found one that resolved it with no loops and it left me with my mouth open. The coder applied Math.min/max , and while I do understand what the code does I don't understand why it works.
I've love to learn because heck, Math.max/min beats the bytes out of my loops for sure.
Given integers n, l and r, find the number of ways to represent n as a sum
of two integers A and B such that l ≤ A ≤ B ≤ r.
Example
For n = 6, l = 2 and r = 4, the output should be
countSumOfTwoRepresentations2(n, l, r) = 2.
There are just two ways to write 6 as A + B, where 2 ≤ A ≤ B ≤ 4: 6 = 2 + 4 and 6 = 3 + 3.
Input/Output
[time limit] 4000ms (js)
[input] integer n
A positive integer.
Constraints:
5 ≤ n ≤ 109.
[input] integer l
A positive integer.
Constraints:
1 ≤ l ≤ r.
[input] integer r
A positive integer.
Constraints:
l ≤ r ≤ 109,
r - l ≤ 106.
The coder's amazing answer:
function countSumOfTwoRepresentations2(n, l, r) {
return Math.max(Math.min(Math.floor(n / 2) - l, r - Math.ceil(n / 2)) + 1, 0);
}
My crap in comparison:
function countSumOfTwoRepresentations2(n, l, r) {
var representations = 0;
//Only travel the loop until n/2 , because l+r will never equal n
// if l or r > n/2
var limit = Math.floor(n/2);
for(var i=l; i<=r && i<=limit; ++i){
for(var j=i;j<=r;++j){
if(i+j == n){
++representations;
break;
}
}
}
return representations;
}

Given integers n, l and r, find the number of ways to represent n as a sum of two integers A and B such that l ≤ A ≤ B ≤ r.
First, consider that if n is even and letting x = n/2, we have at least one solution (x + x) if, and only if, l ≤ x ≤ r. If x isn't in that range then there is no solution, since either x < l and l + l > n or r < x and r + r < n.
That can be generalized to even or odd n: There is a solution if, and only, if: l ≤ floor(x) ≤ ceil(x) ≤ r. If we let A = floor(x) and B = ceil(x), that solution is A + B. Every other solution can be found by taking one step along the number line away from that point in each direction. (A - 1) + (B + 1) = A + B = n, therefore (A - 1) + (B + 1) is a solution as long as (A - 1) hasn't crossed the l boundary and (B + 1) hasn't crossed the r boundary. So, if you wanted a solution with only one loop, you could do something like this:
function countSumOfTwoRepresentations2(n, l, r) {
var x = n/2;
var A = Math.floor( x );
var B = Math.ceil( x );
for ( var count = 0; l <= A && B <= r; count++) {
A--;
B++;
}
return count;
}
But how many times does that loop iterate? Well, it iterates until one of the stopping conditions happens:
A becomes smaller than l
B becomes larger than r
If 1. happens first, then it iterates Math.floor( x ) - l + 1 times, whereas if 2. happens first it iterates r - Math.ceil( x ) + 1 (if both conditions happen on the same iteration, then Math.floor( x ) - l === r - Math.ceil( x )).
As long as there is a solution the loop iterates the smaller of Math.floor( x ) - l + 1 or r - Math.ceil( x ) + 1 times, which is where the coder got the answer Math.min(Math.floor(n / 2) - l, r - Math.ceil(n / 2)) + 1 from (after substituting x back for n/2 and pulling the + 1 out of each term and adding it after instead.
If there is no solution, EG. n = 10, l = 20, r = 20, that formula will give a negative result, but it should give 0 instead, which is why he added Math.max( result, 0 );.
For clarity, the coder's solution could be written as (still with no loops):
function countSumOfTwoRepresentations2(n, l, r) {
var x = n/2;
var A = Math.floor( x );
var B = Math.ceil( x );
// Every solution is of the form (A - i) + (B + i), where i is an integer >= 0
// How many values of i are valid for l <= (A - i)
var stepsA = A - l + 1;
// How many values of i are valid for (B + i) <= r
var stepsB = r - B + 1;
// If the formulas gave a negative amount of valid steps,
// there is no solution, so return 0
if ( stepsA < 0 || stepsB < 0 )
return 0;
// Otherwise, return the smaller valid amount of steps,
// that is the number of steps that are valid for both A and B
return Math.min(stepsA, stepsB);
}

Related

Function with multiple possible arguments that will never return the same value given any sequence of arguments

Let's say you have a function that takes both x and y, real numbers that are integers, as arguments.
What would you put inside that function, using only mathematical operators, so that no two given sequences of arguments could ever return the same value, be it any kind of value?
Example of a function that fails at doing this:
function myfunction(x,y){
return x * y;
}
// myfunction(2,6) and myfunction(3,4) will both return 12
// myfunction(2,6) and myfunction(6,2) also both return 12.
As already noted in comments, at the level of JavaScript numbers such a function can't exist, simply because assuming that we're working with integer-valued IEEE 754 binary64 floats there are more possible input pairs than possible output values.
But to the mathematical question of whether there is a simple, injective function from pairs of integers to a single integer, the answer is yes. Here's one such function that uses only addition and multiplication, so should fit the questioner's "using only mathematical operators" constraint.
First we map each of the inputs from the domain of integers to the domain of nonnegative integers. The polynomial map x ↦ 2*x*x + x will do that for us, and maps distinct values to distinct values. (Sketch of proof: if 2*x*x + x == 2*y*y + y for some integers x and y, then rearranging and factoring gives (x - y) * (2*x + 2*y + 1) == 0; the second factor can never be zero for integers x and y, so the first factor must be zero and x == y.)
Second, given a pair of nonnegative integers (a, b), we map that pair to a single (nonnegative) integer using (a, b) ↦ (a + b)*(a + b) + a. It's easy to see that this, too, is injective: given the value of (a + b)*(a + b) + a, I can recover the value of a + b by taking the integer square root, and from there recover a and b.
Here's some Python code demonstrating the above:
def encode_pair(x, y):
""" Encode a pair of integers as a single (nonnegative) integer. """
a = 2*x*x + x
b = 2*y*y + y
return (a + b)*(a + b) + a
We can easily check that there are no repetitions for small x and y: here we take all pairs (x, y) with -500 <= x < 500 and -500 <= y < 500, and find the set containing encode_pair(x, y) for each combination. If all goes well, we should end up with a set with exactly 1 million entries, one per input combination.
>>> all_outputs = {encode_pair(x, y) for x in range(-500, 500) for y in range(-500, 500)}
>>> len(all_outputs)
1000000
>>> min(all_outputs)
0
But perhaps a more convincing way to establish the injectivity is to give an explicit inverse, showing that the original (x, y) can be recovered from the output. Here's that inverse function. It makes use of Python's integer square root operation math.isqrt, which is available only for Python >= 3.8, but is easy to implement yourself if you need it.
from math import isqrt
def decode_pair(n):
""" Decode an integer produced by encode_pair. """
a_plus_b = isqrt(n)
a = n - a_plus_b*a_plus_b
b = a_plus_b - a
c = isqrt(8*a + 1)
d = isqrt(8*b + 1)
return ((2 - c%4) * c - 1) // 4, ((2 - d%4) * d - 1) // 4
Example usage:
>>> encode_pair(3, 7)
15897
>>> decode_pair(15897)
(3, 7)
Depending on what you allow as a "mathematical operator" (which isn't really a particularly well-defined term), there are tighter functions possible. Here's a variant of the above that provides not just an injection but a bijection: every integer appears as the encoding of some pair of integers. It extends the set of mathematical operators used to include subtraction, division and absolute value. (Note that all divisions appearing in encode_pair are exact integer divisions, without any remainder.)
def encode_pair(x, y):
""" Encode a pair of integers as a single integer.
This gives a bijective map Z x Z -> Z.
"""
ax = (abs(2 * x + 1) - 1) // 2 # x if x >= 0, -1-x if x < 0
sx = (ax - x) // (2 * ax + 1) # 0 if x >= 0, 1 if x < 0
ay = (abs(2 * y + 1) - 1) // 2 # y if y >= 0, -1-y if y < 0
sy = (ay - y) // (2 * ay + 1) # 0 if y >= 0, 1 if y < 0
xy = (ax + ay + 1) * (ax + ay) // 2 + ax # encode ax and ay as xy
an = 2 * xy + sx # encode xy and sx as an
n = an - (2 * an + 1) * sy # encode an and sy as n
return n
def decode_pair(n):
""" Inverse of encode_pair. """
# decode an and sy from n
an = (abs(2 * n + 1) - 1) // 2
sy = (an - n) // (2 * an + 1)
# decode xy and sx from an
sx = an % 2
xy = an // 2
# decode ax and ay from xy
ax_plus_ay = (isqrt(8 * xy + 1) - 1) // 2
ax = xy - ax_plus_ay * (ax_plus_ay + 1) // 2
ay = ax_plus_ay - ax
# recover x from ax and sx, and y from ay and sy
x = ax - (1 + 2 * ax) * sx
y = ay - (1 + 2 * ay) * sy
return x, y
And now every integer appears as the encoding of exactly one pair, so we can start with an arbitrary integer, decode it to a pair, and re-encode to recover the same integer:
>>> n = -12345
>>> decode_pair(n)
(67, -44)
>>> encode_pair(67, -44)
-12345
The encode_pair function above is deliberately quite verbose, in order to explain all the steps involved. But the code and the algebra can be simplified: here's exactly the same computation expressed more compactly.
def encode_pair_cryptic(x, y):
""" Encode a pair of integers as a single integer.
This gives a bijective map Z x Z -> Z.
"""
c = abs(2 * x + 1)
d = abs(2 * y + 1)
e = (2 * y + 1) * ((c + d)**2 * c + 2 * (c - d) * c - 4 * x - 2)
return (e - 2 * c * d) // (4 * c * d)
encode_pair_cryptic gives exactly the same results as encode_pair. I'll give one example, and leave the reader to figure out the equivalence.
>>> encode_pair(47, -53)
-9995
>>> encode_pair_cryptic(47, -53)
-9995
I'm no math wiz but found this question kinda fun so I gave it a shot. This is by no means scalable to large number since I'm using prime numbers as exponents and gets out of control really quick. But tested up to 90,000 combinations and found no duplicates.
The code below has a couple extra functions generateValues() and hasDuplicates() that is just there to run and test multiple values coming from the output of myFunction()
BigNumber.config({ EXPONENTIAL_AT: 10 })
// This function is just to generate the array of prime numbers
function getPrimeArray(num) {
const array = [];
let isPrime;
let i = 2;
while (array.length < num + 1) {
for (let j = 2; (isPrime = i === j || i % j !== 0) && j <= i / 2; j++) {}
isPrime && array.push(i);
i++;
}
return array;
}
function myFunction(a, b) {
const primes = getPrimeArray(Math.max(a, b));
// Using the prime array, primes[a]^primes[b]
return BigNumber(primes[a]).pow(primes[b]).toString();
}
function generateValues(upTo) {
const results = [];
for (let i = 1; i < upTo + 1; i++) {
for (let j = 1; j < upTo + 1; j++) {
console.log(`${i},${j}`)
results.push(myFunction(i,j));
}
}
return results.sort();
}
function hasDuplicates(arr) {
return new Set(arr).size !== arr.length;
}
const values = generateValues(50)
console.log(`Checked ${values.length} values; duplicates: ${hasDuplicates(values)}`)
<script src="https://cdnjs.cloudflare.com/ajax/libs/bignumber.js/8.0.2/bignumber.min.js"></script>
Explanation of what's going on:
Using the example of myFunction(1,3)
And the array of primes [2, 3, 5, 7]
This would take the 2nd and 4th items, 3 and 7 which would result in 3^7=2187
Using 300 as the max generated 90,000 combinations with no duplicates (However it took quite some time.) I tried using a max of 500 but the fan on my laptop sounded like a jet engine taking off so gave up on it.
If x and y are some fixed size integers (eg 8 bits) then what you want is possible if the return of f has at least as many bits as the sum of the number of bits of x an y (ie 16 in the example) and not otherwise.
In the 8 bit example f(x,y) = (x<<8)+y would do. This is because if g(z) = ((z>>8), z&255) then g(f(x,y)) = (x,y). The impossibility comes from the pigeon hole principle: if we want (in the example) to map the pairs (x,y) (of which there 2^16) 1-1 to some integer type, then we must have at least 2^16 values of this type.
function myfunction(x,y){
x = 1/x;
y = 1/y;
let yLength = ("" + y).length
for(let i = 0; i < yLength; i++){
x*=10;
}
return (x + y)
}
console.log(myfunction(2,12))
console.log(myfunction(21,2))
Based on your question and you comments, I understood the following:
You want to pass 2 real numbers into a function. The function should use mathematical operators to generate a new result.
Your question is, if there is any kind of mathematical equation/function you could use, that would ALWAYS deliver a unique result.
If that's so, then the answer is no. You can make your function as complicated as possible and get a result(c) using the two numbers (a & b).
In this case I would look for another combination which could give me the result(c) using the same equation/function. Therefore I would use the system of linear equation to solve this mathematical issue.
In general, a system with fewer equations than unknowns has infinitely many solutions, but it may have no solution. Such a system is known as an underdetermined system.
In our case we would have one equation which gives us one result and two unknowns, therefore it would have infinitely many solutions because we already have a solution, so there is no way for the system to have no solutions at all.
More about this topic.
Edit:
I just recognized that some of us understood the domain of the function in a different way. I was thinking about real numbers (R) but it seems many assumed you talk about integers (Z) only.
Well I guess
real integers
wasnt clear enough, at least for me.
So if we would use integers only, I have no idea if that is possible to always have different results. Some users suggested a topic about that here I am also interested to take a look into that too.

Different results for the same problem solution in node.js and python

I solved the following leetCode problem with some code :
You have d dice, and each die has f faces numbered 1, 2, ..., f.
Return the number of possible ways modulo 10^9 + 7 to roll the dice so the sum of the face up numbers equals t.
I made two versions of the solution code, one in node.js using mathjs, and one in python using the math module .
In node.js
const { combinations: comb, bignumber: Big } = require("mathjs");
function dice(d, f, t) {
if (t > d * f || t < d) return 0;
var result = Big(0);
var i = 0;
var sign = 1;
var n = t - 1;
var k = t - d;
while (k >= 0 && i <= d) {
result = result.add(
comb(Big(d), Big(i))
.times(comb(Big(n), Big(k)))
.times(sign)
);
i++;
n -= f;
k -= f;
sign *= -1;
}
return result;
}
console.log(
dice(30, 30, 500).mod(
Big(10)
.pow(9)
.add(7)
)
);
In python :
import math
def dice(d, f, t):
if t > d * f or t < d:
return 0
result = 0
i = 0
sign = 1
n = t - 1
k = t - d
while k >= 0 and i <= d:
result += math.comb(d, i) * math.comb(n, k) * sign
i += 1
n -= f
k -= f
sign *= -1
return result
print(dice(30, 30, 500) % (math.pow(10, 9) + 7))
Now when i run the code with these parameters : d=30 f=30 t=500 (the last line of each version of the code), i expect the result to be 222616187 .
In the node.js version , that's exactly what i get .
But in the python version , i'm getting 811448245.0 i can't figure out why is that happening .
So why is there a difference in the results ?
The math module usesfloat, not arbitrary precision int.
math - Mathematical functions
[...]
The following functions are provided by this module. Except when
explicitly noted otherwise, all return values are floats.
Since math.pow returns a float, the leading argument to % is converted to a float as well.
The result of dice(30, 30, 500) is too large to be accurately represented as a float. Its float representation is off by -14999044413600247749080617.
The ** operator and its function version operator.pow do not force float conversion and provide an integer if all parameters are integers.
>>> print(dice(30, 30, 500) % (10 ** 9 + 7))
222616187
Solved, in a weird way. It turns out, math.pow returns a float instead of int and somehow bugged. I think int % float has a different cast operation in it and treated differently by the compiler. It can be investigated further. If you cast it to int, that would be your answer.
import math
def dice(d, f, t):
if t > d * f or t < d:
return 0
result = 0
i = 0
sign = 1
n = t - 1
k = t - d
while k >= 0 and i <= d:
result += math.comb(d, i) * math.comb(n, k) * sign
i += 1
n -= f
k -= f
sign *= -1
return result
print(dice(30, 30, 500) % int((math.pow(10, 9) + 7)))

Round to the nearest factor of N

Given a number, x (like 13), and a factor N (like 2), how can I compute the values 8 and 16 below?
8 <= 13 < 16
In other words, how can I compute the two ends of the equality here:
N^? <= x < N^(? + 1)
You could take the floored nth logarithm of the number and use it as value for getting the power of f and f plus one.
function getInterval(x, n) {
var f = Math.floor(Math.log(x) / Math.log(n));
return [Math.pow(n, f), Math.pow(n, f + 1)];
}
console.log(getInterval(3, 2).join(' '));
console.log(getInterval(23, 7).join(' '));
console.log(getInterval(13, 2).join(' '));
Edit. Question sense was completely changed.
pwr = Math.floor(Math.log(x) / Math.log(n))
low = Math.pow(n, pwr)
high = Math.pow(n, pwr + 1)

How to implement carousel with an array

I have an array of items representing a virtual carousel.
const carousel = ['a','b','c','d','e'];
let currentIndex = 0;
function move (amount) {
const l = items.length; // in case carousel size changes
// need to update currentIndex
return carousel[currentIndex];
}
What is a clean or clever way to handle moving left when currentIndex == 0 and moving right when currentIndex == length-1?
I have thought about this before and have never come with anything very clever or concise.
short answer
Implement a circular array via modular arithmetic. Given a distance to move, to calculate the appropriate index:
// put distance in the range {-len+1, -len+2, ..., -1, 0, 1, ..., len-2, len-1}
distance = distance % len
// add an extra len to ensure `distance+len` is non-negative
new_index = (index + distance + len) % len
long answer
Use modular arithmetic much like how you'd read a typical analog clock. The premise is to add two integers, divide by a integer, and keep the remainder. For example, 13 = 3 (mod 10) because 13 is 1*10 + 3 and 3 is 0*10 + 3.
But why did we choose to arrange 3 and 13 as we did? To answer that, we consider the Euclidean division algorithm (EDA). It says for two integers a and b there exists unique integers q and r such that
a = b*q + r
with 0 ≤ r < b. This is more powerful than you'd think: it allows us to "work modulo n."
That is, we can say a = b (mod n) iff there are unique integers q1, r1, q2, and r2 such that
a = n * q1 + r1, 0 ≤ r1 < n
b = n * q2 + r2, 0 ≤ r2 < n
and r1 equals r2. We call r1 and r2 the "remainders."
To go back to the previous example, we now know why 13 = 3 (mod 10). The EDA says 13 = 1*10 + 3 and that 1 and 3 are the only q and r satisfying the necessary constraints; by similar logic, 3 = 0*10 + 3. Since the remainders are equal, we say that 13 and 3 are equal when "working mod 10."
Fortunately, JavaScript implements a modulo operator natively. Unfortunately, we need to watch out for a quirk, i.e., the modulo operator keeps the sign of its operands. This gives you some results like -6 % 5 == -1 and -20 % 7 == -6. While perfectly valid mathematical statements (check why), this doesn't help us when it comes to array indices.
Lemma 1: a + n = a (mod n)
Lemma 2: -1 = n-1 (mod n)
Lemma 3: -a = n-a (mod n)
The way to overcome this is to "trick" JavaScript into using the correct sign. Suppose we have an array with length len and current index index; we want to move the index by a distance d:
// put `d` within the range {-len+1, -len+2, ..., -2, -1, -0}
d = d % len
// add an extra len to ensure `d+len` is non-negative
new_index = (index + d + len) % len
We accomplish this by first putting d within the range {-len+1, -len+2, ..., -2, -1, -0}. Next, we add an extra len to make sure the distance we're moving is within the range {1, 2, ..., len-1, len}, thereby ensuring the result of the % operation has a positive sign. We know this works because (-a+b) + a = b (mod a). Then we just set the new index to index + d + len (mod len).
More detailed implementation:
class Carousel {
// assumes `arr` is non-empty
constructor (arr, index = 0) {
this.arr = arr
this.index = index % arr.length
}
// `distance` is an integer (...-2, -1, 0, 1, 2, ...)
move (distance) {
let len = this.arr.length
distance = distance % len
let new_index = (this.index + distance + len) % len
this.index = new_index
return this.arr[this.index]
}
}
// usage:
let c = new Carousel(['a','b','c','d','e'], 1) // position pointer set at 'b'
c.move(-1) // returns 'a' as (1 + -1 + 5) % 5 == 5 % 5 == 0
c.move(-1) // returns 'e' as (0 + -1 + 5) % 5 == 4 % 5 == 4
c.move(21) // returns 'a' as (4 + 21 + 5) % 5 == 30 % 5 == 0
I had implemented an Array.prototype.rotate() a while back. It might come very handy for this job. Here is the code;
Array.prototype.rotate = function(n) {
var len = this.length;
return !(n % len) ? this.slice()
: this.map((e,i,a) => a[(i + (len + n % len)) % len]);
};
var a = [1,2,3,4,5,6,7,8,9],
b = a.rotate(10);
console.log(JSON.stringify(b));
b = a.rotate(-10);
console.log(JSON.stringify(b));
currentIndex = currentIndex + change;
if (currentIndex >= l) currentIndex = 0;
if (currentIndex < 0) currentIndex = l - 1;
This will modify the index, check if it's broken possible values and adjust to either 'side' of the carousel.

Getting random number divisible by 16

In math how do I obtain the closest number of a number that is divisible by 16?
For example I get the random number 100 and I want to turn that number (using a math function) into the closest number to 100 that is divisible by 16 (In this case its 96)
I'm trying to do this in JavaScript but if I knew the math formula for it I would easily do it in any language.
Thank you,
Regards
Generate a random integer. Multiply it by 16.
Divide by 16, round, and multiply by 16:
n = Math.round(n / 16) * 16;
function GetRandomNumberBetween(lo, hi) {
return Math.floor(lo + Math.random() * (hi - lo));
}
Number.prototype.FindClosestNumberThatIsDivisibleBy = function(n) {
return Math.round(this / n) * n; //simplify as per Guffa
/* originally:
var c = Math.ceil(n);
var f = Math.floor(n);
var m = num % n;
var r = f * n;
if (m > (n / 2))
r = c * n;
return r;
*/
};
var r = GetRandomNumberBetween(10, 100);
var c = r.FindClosestNumberThatIsDivisibleBy(16);
function closest(n) {
var r = 0, ans = 0;
r = n % 16
if r < 8 {
ans = n - r
} else {
ans = n + (16 - r)
}
return ans;
}
Here's how I understand your question. You're given a number A, and you have to find a number B that is the closest possible multiple of 16 to A.
Take the number given, "A" and divide it by 16
Round the answer from previous step to the nearest whole number
multiply the answer from previous step by 16
there's the pseudocode, hope it's what you're looking for ;-)
A general JS solution
var divisor = 16;
var lower = 0;
var upper = 100;
var randDivisible = (Math.floor(Math.random()*(upper-lower))+lower)*divisor;
alert(randDivisible);

Categories