0

Due to the constraints of some dev tools, I'm looking for a mathematical expression of:

If x>=1:
    y = 1
else:
    y = 0

if it adds simplicity, X must be an integer greater or equal to 0.

The operations that are definitely allowed: +, -, /, *, ** (power)

Not allowed operations: use of absolute value is not allowed. use of >, <, <=, >=, !=, == is not allowed. use of "if"

For instance Not allowed: y = 1*(x>=1)

(due to the use of >=)

For added information, I am trying to add some constraints to google's or-tools, where if X>=0 then, y+=1...

Edit: I am working in python.

user1639926
  • 852
  • 2
  • 11
  • 21
  • 5
    You are looking for the [sign function](https://en.wikipedia.org/wiki/Sign_function). – derpirscher Mar 07 '21 at 11:46
  • 1
    `y = 1 - 0**x`? (Depending on what your tool thinks `0**0` is, of course.) – Mark Dickinson Mar 07 '21 at 12:30
  • @user1639926 Are logical operators allowed: AND, OR, XOR, NOT? – njuffa Mar 07 '21 at 12:58
  • @user1639926 Is it known how many bits the integer comprises? – njuffa Mar 07 '21 at 13:08
  • is `x` an integer? and is `/` a truncated division (i.e. integer division) or a normal floating-point one? – phuclv Mar 07 '21 at 14:10
  • 1
    What does 0/0 do in your language? I'm thinking `y = x / x` might work. – kaya3 Mar 07 '21 at 15:35
  • This might help: https://stackoverflow.com/a/1986776/1220550 – Peter B Mar 08 '21 at 17:28
  • @kaya3 Strictly mathematical speaking: `0/0` can be anything from `-inf` to `+inf`, especally it can be `0`, `1` or even `undefined`, depending on the context. Typically, programming languages on `0/0` either return `NaN` (if available) or throw an exception – derpirscher Mar 08 '21 at 18:42
  • @derpirscher The question is about integer arithmetic, `NaN` is a floating-point value, not an integer value. Higher-level languages indeed deal with it by throwing an exception, but e.g. in C the behaviour is unspecified and some implementations will treat it as 0 because that's what the CPU's integer division operation does, and in some other low-level languages, 0 is the specified result. Hence my comment. – kaya3 Mar 08 '21 at 19:18

5 Answers5

3

I'd say there is no way to get a discontinue function defined everywhere like y(x) using a finite number of continuous functions with composition and continuous operators only.

You can get something like abs(x) with (x ** 2) ** 0.5 but I don't see how you can use this (that has a discontinuous first derivative but that is still continuous) to get a perfect step function defined everywhere with assigned value at step point.

Something like 0.5 + 0.5 * abs(x-1)/(x-1) is what you're looking for almost everywhere, but you're going to have problems for the singularity x=1 where 0/0 is going to be evaluated.

EDIT

If input x is guaranteed to be an integer then the solution is easy:

def y(x):
    return 0.5 + 0.5 * abs(x - 0.5) / (x - 0.5)

or, defining abs using power...

def y(x):
    return 0.5 + 0.5 * ((x - 0.5) ** 2) ** 0.5 / (x - 0.5)

The function is undefined for x=0.5 but if it's evaluated only on integers this is not a problem.

Another option is

def y(x):
    return 0.5 + abs(x - 0.25) + (x - 0.25) - abs(abs(x-0.25) + (x-0.25) - 0.5)

that is a continuous function that is 0 before 0.25, goes linearly from 0 to 1 as x goes from 0.25 to 0.75 and stays to 1 after it.

6502
  • 112,025
  • 15
  • 165
  • 265
  • It is quite possible to have a continuous function which takes the required values at integers, since there is no requirement about what values it takes at non-integers. – kaya3 Mar 07 '21 at 15:38
  • @kaya3: in that cas the solution is simple... see edit – 6502 Mar 07 '21 at 15:47
  • @kaya3: rereading the question it's even simpler because x is not only an integer but also >=0. So what is looked for is a function that is 0 for 0 and 1 for anything else... – 6502 Mar 07 '21 at 15:50
0

Since the integer is known to be non-negative, one can simply OR together all of the bits of the integer one-by-one. The result is the desired predicate. A simple loop that performs bit-wise OR-ing until the source operand is exhausted requires a comparison, which is not allowed.

The only workable alternative under the restrictions imposed that I can see right now is to use straight-line code that repeats the bit extraction process for as many steps as the integer has bits. This is what I use in the ISO-C99 code below. Each bit is extracted with DIV and MOD. OR of two one-bit variables s and t is computed as s + t - s * t. A simple exhaustive test for 32-bit integers confirms that this approach if functional, but the efficiency is obviously not great.

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define OR1(s,t)  (s + t - s * t)

// (x >= 1) ? 1 : 0
uint32_t ge1 (uint32_t x)
{
    uint32_t y;

    y = OR1 (
             OR1 (
                 OR1 (OR1 (OR1 ((x / 0x00000001) % 2, (x / 0x00000002) % 2),
                           OR1 ((x / 0x00000004) % 2, (x / 0x00000008) % 2)),
                      OR1 (OR1 ((x / 0x00000010) % 2, (x / 0x00000020) % 2),
                           OR1 ((x / 0x00000040) % 2, (x / 0x00000080) % 2))),
                 OR1 (OR1 (OR1 ((x / 0x00000100) % 2, (x / 0x00000200) % 2),
                           OR1 ((x / 0x00000400) % 2, (x / 0x00000800) % 2)),
                      OR1 (OR1 ((x / 0x00001000) % 2, (x / 0x00002000) % 2),
                           OR1 ((x / 0x00004000) % 2, (x / 0x00008000) % 2)))), 
             OR1 (
                 OR1 (OR1 (OR1 ((x / 0x00010000) % 2, (x / 0x00020000) % 2),
                           OR1 ((x / 0x00040000) % 2, (x / 0x00080000) % 2)),
                      OR1 (OR1 ((x / 0x00100000) % 2, (x / 0x00200000) % 2),
                           OR1 ((x / 0x00400000) % 2, (x / 0x00800000) % 2))),
                 OR1 (OR1 (OR1 ((x / 0x01000000) % 2, (x / 0x02000000) % 2),
                           OR1 ((x / 0x04000000) % 2, (x / 0x08000000) % 2)),
                      OR1 (OR1 ((x / 0x10000000) % 2, (x / 0x20000000) % 2),
                           OR1 ((x / 0x40000000) % 2, (x / 0x80000000) % 2)))));
    return y;
}

int main (void)
{
    uint32_t x, res, ref;

    x = 0;
    do {
        res = ge1 (x);
        ref = x >= 1;
        if (res != ref) {
            printf ("error: x=%08x  res=%08x  ref=%08x\n", x, res, ref);
            return EXIT_FAILURE;
        }
        x++;
    } while (x);
    printf ("test passed\n");
    return EXIT_SUCCESS;
}
njuffa
  • 23,970
  • 4
  • 78
  • 130
0

In this case I would suggest the following: As x is integer and x>=0 the following logic wil be true:

if x > 0 then 0**x == 0 else 0**x == 1. This is equal to if x >=1 then 0**x == 0 else 0**x == 1.

So y = 1 - 0**x will give the desired result.

asd-tm
  • 3,381
  • 2
  • 24
  • 41
  • Well, that strongly depends on how `0**0` is evaluated in the respective tool. There are good arguments for and against both `0**0 == 1` and `0**0 == 0` – derpirscher Mar 08 '21 at 09:43
  • @derpirscher If we are talking about mathematics, mathematically 0**0 equals to 1. You can check it using a calculator. Note especially that the Q is tagged only as `math` and no specific tools are mentioned. – asd-tm Mar 08 '21 at 14:55
  • No, especially if we talk about "mathematics" there is no definitive answer, what the result of `0**0` is. Just because some random calculator returns a certain number, that does not mean, it's correct ... You are right, most systems will return `1`, and also certain fields of mathematics use `1` but others tend to assume its value undefined https://en.wikipedia.org/wiki/Zero_to_the_power_of_zero – derpirscher Mar 08 '21 at 15:18
  • @derpirscher You are right. The only argument I can present is that the function we are talking about is not continuous. It takes only integer values. Thank you once again for your comment. – asd-tm Mar 08 '21 at 18:24
  • that has nothing to do with continuous or not. On the one hand `x**0 == 1` for all `x`, on the other hand `0**x == 0` for all `x`. So if you put in `x = 0` in both cases, you get a contradiction. I'm not a mathematician myself, but depending on who you asked at university, you got different answers, ie 0, 1, undefined, or "it depends ..." – derpirscher Mar 08 '21 at 18:32
0

Lets see here, you basically have an inequality x-1>=0.

y = (x-1)/abs(x-1) will give you the value you are looking for for all cases except for when x=0. In this case an exception will be thrown, perhaps you can use that to set the value of y. so something like:

try{
y=(x-1)/abs(x-1);
} catch(ArithmaticException e){
y = 1}
  • The OP indicated use of `abs` was not allowed. But it seems to me this is not unreasonable... why not just use y = x/x and catch the error let y = 0? OP also indicated x will be an non-negative integer. – andand Mar 09 '21 at 17:11
0

For integer x, if abs is OK, then I suggest

y = (x + abs(x)) / (abs(x+1) + abs(x-1))

This is not subject to division by zero, and division is exact for every integer x, positive or negative, as long as no overflow occurs, so it can be evaluated with integer arithmetic.

If you don't care of negative x, it's even simpler:

y = (abs(x+1) - abs(x-1)) / 2

If the function needs to operate on a whole domain of bounded integers, then some larger int arithmetic shall be used, or you can use same function in floating point arithmetic with float(x), or could equally fall back to the answer of @6502 which is simpler in this case.

EDIT if you don't have an absolute value, you could try 1-(2.0**(-x))**n, with large enough n so as to exploit floating point underflow and/or limited precision. n=2000 should be enough to cause underflow for every positive integer input, but no use to have n that high, since n=100 should be enough to cause inexact rounding to 1 on most architectures. Even with floating point arithmetic, it's quite simple to evaluate efficiently, you can use a single power 1.0-(2.0**(-100.0*x)). For negative integer input, replace x with x*x.

aka.nice
  • 9,100
  • 1
  • 28
  • 40