3

Given positive-integer inputs x and y, is there a mathematical formula that will return 1 if x==y and 0 otherwise? I am in the unfortunate position of having to use a tool that only allows me to use the following symbols: numerals 0-9; decimal point .; parentheses ( and ); and the four basic arithmetic operations +, -, /, and *.

Currently I am relying on the fact that the tool that evaluates division by zero to be zero. (I can't tell if this is a bug or a feature.) Because of this, I have been able to use ((x-y)/(y-x))+1. Obviously, this is ugly and unideal, especially in the case that it is a bug and they fix it in a future version.

  • Nope. Math doesn't work like that (your expression there, `((x-y)/(y-x))+1` should actually throw a divide-by-zero error if `x` and `y` are equal). – Draco18s no longer trusts SE Feb 01 '16 at 21:39
  • @Draco18s not in math, but in OP's tool; see OP's last paragraph! – Marcus Müller Feb 01 '16 at 21:41
  • @MarcusMüller I missed that. If that's the case, then `((x-y)/(y-x))+1` would be the only way. – Draco18s no longer trusts SE Feb 01 '16 at 21:42
  • by the way, that's an extremely clever approach, Jeremiah! – Marcus Müller Feb 01 '16 at 21:43
  • 1
    um, what *awesome* tool are you using? – Marcus Müller Feb 01 '16 at 21:48
  • Since this is not a math site, can the solution take advantage of using integer math as defined by a computer language? – chux - Reinstate Monica Feb 01 '16 at 21:48
  • @chux, considering there's a decimal point available: probably not. – Marcus Müller Feb 01 '16 at 21:48
  • 1
    @MarcusMüller the inputs are integers. Using DP is optional. – chux - Reinstate Monica Feb 01 '16 at 21:50
  • Dear OP, **we need clarification**. – Marcus Müller Feb 01 '16 at 22:30
  • The tool in question is a form-builder (ugh…), and I wish I could tell you which language its math-evaluation is running in, but it's seeming to me that it's evaluating/validating it both client-side (JavaScript) and server-side. (Sorry for the delay; I was busy for a while.) –  Feb 01 '16 at 22:40
  • @JeremiahMegel: The question is whether 3/2 is 1 or 1.5. – rici Feb 01 '16 at 23:16
  • There is no truncation. So 3/2 == 1.5 –  Feb 02 '16 at 02:41
  • JeremiahMegel: Ah. In that case, I fear that @MarcusMüller is correct and there is no solution. (Unless you would be satisfied by x==y being 1 and x!=y being positive but less than 1, and I suspect that won't fit your use case.) – rici Feb 02 '16 at 07:39
  • If this is purely a mathematical question, why post here rather than http://math.stackexchange.com/? What is the programming aspect of this post? – chux - Reinstate Monica Feb 02 '16 at 17:22
  • @chux I considered it, but I felt that its nature was more in the computer-science area of mathematics, and that programmers might have more experience with this sort of problem than general mathematicians. –  Feb 02 '16 at 18:03
  • In programming, there is non-perfect math, like `1.0/3.0` --> `0.33333333333333331482961625...` rather than `.3333...` and integer math `1/3` --> `0`. So if you want theory, go to the math site (and I think there is then no solution), yet if you want programming, tag the post of the programming language of interest. Else I assert `(x/y) * (y/x)` is a fine programming solution using integer math. – chux - Reinstate Monica Feb 02 '16 at 18:13
  • The thing is: I don't for sure know which programming language is going to be evaluating this. I know that JavaScript is going to be doing it client-side, but I have no idea about server-side. –  Feb 02 '16 at 18:18

3 Answers3

1

Taking advantage of integer division in C truncates toward 0, the follows works well. No multiplication overflow. Well defined for all "positive-integer inputs x and y".

(x/y) * (y/x)

#include <stdio.h>
#include <limits.h>

void etest(unsigned x, unsigned y) {
  unsigned ref = x == y;
  unsigned z =  (x/y) * (y/x);
  if (ref != z) {
    printf("%u %u %u %u\n", x,y,z,ref);
  }
}

void etests(void) {
  unsigned list[] = { 1,2,3,4,5,6,7,8,9,10,100,1000, UINT_MAX/2 , UINT_MAX - 1, UINT_MAX };
  for (unsigned x = 0; x < sizeof list/sizeof list[0]; x++) {
    for (unsigned y = 0; y < sizeof list/sizeof list[0]; y++) {
      etest(list[x], list[y]);
    }
  }
}

int main(void) {
  etests();
  printf("Done\n");
  return 0;
}

Output (No difference from x == y)

Done
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Very nice. I don't know that the complexity of my solution is justified by the fact that it works even if x or y are 0. – rici Feb 01 '16 at 23:15
  • @rici Thanks, Did not sound like `x,y==0` was important. Easy to adjust here with `((x+1)/(y+1)) * ((y+1)/(x+1))`, but now loose use of `UINT_MAX`. – chux - Reinstate Monica Feb 01 '16 at 23:21
  • that just shifts the problem from 0 to -1 :) Using the square of the difference works with any values at all, as long as you can deal with overflow. – rici Feb 01 '16 at 23:22
1

If division is truncating and the numbers are not too big, then:

((x - y) ^ 2 + 2) / ((x - y) ^ 2 + 1) - 1

The division has the value 2 if x = y and otherwise truncates to 1.

(Here x^2 is an abbreviation for x*x.)

This will fail if (x-y)^2 overflows. In that case, you need to independently check x/k = y/k and x%k = y%k where (k-1)*(k-1) doesn't overflow (which will work if k is ceil(sqrt(INT_MAX))). x%k can be computed as x-k*(x/k) and A&&B is simply A*B.

That will work for any x and y in the range [-k*k, k*k].

A slightly incorrect computation, using lots of intermediate values, which assumes that x - y won't overflow (or at least that the overflow won't produce a false 0).

  int delta = x - y;
  int delta_hi = delta / K;
  int delta_lo = delta - K * delta_hi;
  int equal_hi = (delta_hi * delta_hi + 2) / (delta_hi * delta_hi + 1) - 1;
  int equal_lo = (delta_lo * delta_lo + 2) / (delta_lo * delta_lo + 1) - 1;
  int equals = equal_hi * equal_lo;

or written out in full:

((((x-y)/K)*((x-y)/K)+2)/(((x-y)/K)*((x-y)/K)+1)-1)*
((((x-y)-K*((x-y)/K))*((x-y)-K*((x-y)/K))+2)/
 (((x-y)-K*((x-y)/K))*((x-y)-K*((x-y)/K))+1)-1)

(For signed 31-bit integers, use K=46341; for unsigned 32-bit integers, 65536.)

Checked with @chux's test harness, adding the 0 case: live on coliru and with negative values also on coliru.

On a platform where integer subtraction might produce something other than the 2s-complement wraparound, a similar technique could be used, but dividing the numbers into three parts instead of two.

rici
  • 234,347
  • 28
  • 237
  • 341
0

So the problem is that if they fix division by zero, it means that you cannot use any divisor that contains input variables anymore (you'd have to check that the divisor != 0, and implementing that check would solve the original x-y == 0 problem!); hence, division cannot be used at all.

Ergo, only +, -, * and the association operator () can be used. It's not hard to see that with only these operators, the desired behaviour cannot be implemented.

Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
  • "you'd have to check that the divisor != 0," --> it is known `x,y` are positive. – chux - Reinstate Monica Feb 01 '16 at 22:15
  • "It's not hard to see that with only these operators, the desired behaviour cannot be implemented." Apparently, that proposition is not as obvious as it might have appeared :-) – rici Feb 01 '16 at 22:26
  • @rici I was assuming that the math involved pretty much operates "normally" over the field of rational numbers, with the zero-division exception, and is not integer arithmetic. in fact, OP never stated such, and so I stand by that assumption until OP explains what he meant :) – Marcus Müller Feb 01 '16 at 22:28