122

I am working with software (Oracle Siebel) that only supports JavaScript expressions with operators multiply, divide, subtract, add, and XOR (*, /, -, +, ^). I don't have other operators such as ! or ? : available.

Using the above operators, is it possible to convert a number to 1 if it is non-zero and leave it 0 if it's already zero? The number may be positive, zero, or negative.

Example:

var c = 55;

var d;  // d needs to set as 1

I tried c / c , but it evaluates to NaN when c is 0. d needs to be 0 when c is 0.

c is a currency value, and it will have a maximum of two trailing digits and 12 leading digits.

I am trying to emulate an if condition by converting a number to a Boolean 0 or 1, and then multiplying other parts of the expression.

Dai
  • 141,631
  • 28
  • 261
  • 374
yas
  • 3,520
  • 4
  • 25
  • 38
  • 3
    Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/182540/discussion-on-question-by-dave-can-mathematical-operators-be-used). – Samuel Liew Oct 26 '18 at 03:09
  • 10
    @SamuelLiew Although there are a lot of comments, and some of them should be removed ([discussion](https://chat.stackoverflow.com/transcript/message/44387615#44387615), [answer in comment](https://chat.stackoverflow.com/transcript/message/44387620#44387620)), most of them are really request for clarification ([for example](https://chat.stackoverflow.com/transcript/message/44387622#44387622)). [Comments asking whether it's an XY problem](https://chat.stackoverflow.com/transcript/message/44387618#44387618) is borderline. – user202729 Oct 26 '18 at 12:50
  • Oracle Siebel Numeric Operators, seems to be Exponent: https://docs.oracle.com/cd/E95904_01/books/VBLANG/Using_Siebel_VB16.html#wp1004585 – Derrick Moeller Oct 26 '18 at 19:49
  • 2
    @DerrickMoeller It seems there is a distinction between Siebel VB and Siebel eScript. [In the latter, it is a bitwise xor](https://docs.oracle.com/cd/B40099_02/books/eScript/eScript_JSLOverview28.html). I'm not sure which of the two applies here. – CRice Oct 26 '18 at 20:05
  • @CRice if OP says JavaScript then xor it is. But then `^` is a bitwise operator so other bitwise operators should be allowed too. – Salman A Oct 27 '18 at 20:32
  • 3
    @user202729 once any entire comment thread gets too long, we are not going to individually treat comments differently, as the mod interface created by SE admins/devs prefers our default actions to be either "move to chat" or "delete all". If any comment is useful, it should be edited into the question itself or posted as an answer. If any comment is off-topic, they should have been self-pruned/deleted. If you would like to discuss this mod "feature" and/or the "too many comments" auto flags moderators get, please do bring it up for discussion on Meta or Meta.SE. Thank you. – Samuel Liew Oct 28 '18 at 03:54

4 Answers4

219

Use the expression n/n^0.

If n is not zero:

 Step    Explanation
------- -------------------------------------------------------------------------------
 n/n^0   Original expression.
 1^0     Any number divided by itself equals 1. Therefore n/n becomes 1.
 1       1 xor 0 equals 1.

If n is zero:

 Step    Explanation
------- -------------------------------------------------------------------------------
 n/n^0   Original expression.
 0/0^0   Since n is 0, n/n is 0/0.
 NaN^0   Zero divided by zero is mathematically undefined. Therefore 0/0 becomes NaN.
 0^0     In JavaScript, before any bitwise operation occurs, both operands are normalized.
         This means NaN becomes 0.
 0       0 xor 0 equals 0.

As you can see, all non-zero values get converted to 1, and 0 stays at 0. This leverages the fact that in JavaScript, NaN^0 is 0.

Demo:

[0, 1, 19575, -1].forEach(n => console.log(`${n} becomes ${n/n^0}.`))
MultiplyByZer0
  • 6,302
  • 3
  • 32
  • 48
CRice
  • 29,968
  • 4
  • 57
  • 70
  • 45
    TIL: `Number.NaN ^ n === n` o_O (where `n` is a finite number) – zerkms Oct 25 '18 at 00:51
  • 17
    It seems that when used as a bitwise operand, `NaN` is conveniently converted to zero. See: [Bitwise operations on non numbers](https://stackoverflow.com/questions/11037811/bitwise-operations-on-non-numbers) – CRice Oct 25 '18 at 00:57
  • 3
    @zerkms Maybe `~~NaN === 0` seems more natural – Bergi Oct 25 '18 at 18:24
  • Do multiplication and exponentiation have the same precedence in JavaScript? – Enrico Borba Oct 26 '18 at 01:36
  • 9
    @EnricoBorba It is not exponentiation (which uses `**`), it is a bitwise XOR. Bitwise operations have a very low precedence in javascript so the division will happen first. – CRice Oct 26 '18 at 01:37
  • Oh duh... Sorry, been using haskell too much recently. – Enrico Borba Oct 26 '18 at 01:52
  • 1
    Notie that this is similar to `(n/n) ^ 0`, which will be `1 ^ 0` except for falsy values which will be `0 ^ 0`. – Ismael Miguel Oct 26 '18 at 11:13
  • 1
    @zerkms: `Number.NaN ^ n` is defined. Meanwhile, `-1**2` is a syntax error. :-/ – Eric Duminil Oct 26 '18 at 15:36
  • 3
    `^` is bitwise xor operator. I doubt if `^` in the OP is bitwise xor when all other operators are arithmetic operators. It is probably the exponentiation operator (`**` in JavaScript). – Salman A Oct 26 '18 at 19:57
150

c / (c + 5e-324) should work. (The constant 5e-324 is Number.MIN_VALUE, the smallest representable positive number.) If x is 0, that is exactly 0, and if x is nonzero (technically, if x is at least 4.45014771701440252e-308, which the smallest non-zero number allowed in the question, 0.01, is), JavaScript's floating-point math is too imprecise for the answer to be different than 1, so it will come out as exactly 1.

  • 1
    you need to convert the expression to bool first, since the OP is trying to multiply 0 and 1 with `other parts of the expression`, and `c / (c + 5e-324) * some_expression` won't work – phuclv Oct 25 '18 at 04:14
  • 29
    Taken a bug and turned it into a feature there – Chirag Bhatia - chirag64 Oct 25 '18 at 19:33
  • 1
    @Medinoc yes, but the question also says that there will never be more than 2 digits after the decimal point, and 324 is a lot more than 2. – Joseph Sible-Reinstate Monica Oct 26 '18 at 12:56
  • 1
    It's interesting and it might work for OP, but I'd really hate to come across this kind of code when working in a team. At the very least, it should be well documented and tested. – Eric Duminil Oct 26 '18 at 15:33
  • 2
    @JosephSible I know, but if you really take it that way, the most obvious answer should be `Number(Boolean(n))`, which uses no operator. I didn't say this is not what the answer the OP was looking for, but this is not the answer to the question the OP described. Probably should improve the question though. – zypA13510 Oct 27 '18 at 05:18
  • @zypA13510 In that context, each () is a function call operator, so no, that wouldn't meet the requirements. – Joseph Sible-Reinstate Monica Oct 27 '18 at 15:44
  • @zypA13510 FYI `NaN-NaN` is `NaN`, so you actually need the constant zero to make that answer work for all inputs. – Bakuriu Oct 27 '18 at 20:37
  • 1
    What if the constant is exactly `-5e-324`? – Thomas Baruchel Oct 28 '18 at 08:26
  • @ThomasBaruchel then it will break, but the asker said there will never be more than 2 digits after the decimal place, so this won't be a problem for them. – Joseph Sible-Reinstate Monica Oct 28 '18 at 13:26
  • This method doesn't seem ideal to me, simply because it's depending on specific properties of the underlying system (the floating point format, the size of the floating point type, possibly other things) that could subtly change things in the future. I'd highly recommend OP find a more dependable solution than this. That being said, I myself couldn't think of a solution, so there's that... :) – Steve Oct 28 '18 at 21:56
  • @JosephSible Whether something is acceptable depends on whether OP's "system" accept it, and it's not very clear and some people believe that OP's description is wrong. – user202729 Oct 29 '18 at 11:18
  • It seems to be very puzzling... I would avoid using it in production or while working in a team. However I really like the way you turned a language limitation into a feature (I upvoted it). – CFV Oct 29 '18 at 18:21
17

(((c/c)^c) - c) * (((c/c)^c) - c) will always return 1 for negatives and positives and 0 for 0.

It is definitely more confusing than the chosen answer and longer. However, I feel like it is less hacky and not relying on constants.

EDIT: As @JosephSible mentions, a more compact version of mine and @CRice's version which does not use constants is:

c/c^c-c
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kyle Wardle
  • 828
  • 6
  • 23
2

A very complicated answer, but one that doesn't depend on limited precision: If you take x^(2**n), this will always be equal to x+2**n if x is zero, but it will be equal to x-2**n if x has a one in the nth place. Thus, for x=0, (x^(2**n)-x+2**n)/(2**(n+1) will always be 1, but it will sometimes be zero for x !=0. So if you take the product of (x^(2**n)-x+2**n)/(2**(n+1) over all n, then XOR that with 1, you will get your desired function. You'll have to manually code each factor, though. And you'll have to modify this if you're using floating points.

If you have the == operator, then (x==0)^1 works.

Acccumulation
  • 3,491
  • 1
  • 8
  • 12