25
\$\begingroup\$

Ash has a bit of an interesting float division algorithm. It's designed to never return NaN, and things like signed zero and infinity need to be handled.

How it works:

Assume the inputs are positive for the rules below. One input being negative will always result in the output being negative, and both being negative will result in a positive output.

  • Zero divided by anything is 0
  • Anything other than 0 divided by 0 is Infinity
  • Anything other than Infinity divided by Infinity is 0
  • Infinity divided by anything other than Infinity is Infinity
  • Infinity divided by Infinity is 1
  • All other division works as normal

I/O:

For languages with floats that support signed zero and positive/negative infinity, floats are an accepted I/O format. For others, using a string is allowed. You can use any reasonable format in this string, and you can represent the infinities with anything that can't be confused with another number (such as I, , inf, or :().

Input will always be two floats in your chosen representation, and output will be a single one. Floating point errors and large numbers being represented as Infinity are allowed.

Test cases:

0 / 0                   0
0 / 1                   0
0 / 8                   0
0 / Infinity            0
0 / -0                 -0
0 / -1                 -0
0 / -8                 -0
0 / -Infinity          -0
-0 / 0                 -0
-0 / 1                 -0
-0 / 8                 -0
-0 / Infinity          -0
-0 / -0                 0
-0 / -1                 0
-0 / -8                 0
-0 / -Infinity          0
1 / 0                   Infinity
8 / 0                   Infinity
Infinity / 0            Infinity
1 / -0                 -Infinity
8 / -0                 -Infinity
Infinity / -8          -Infinity
-1 / 0                 -Infinity
-8 / 0                 -Infinity
-Infinity / 0          -Infinity
-1 / -0                 Infinity
-8 / -0                 Infinity
-Infinity / -0          Infinity
Infinity / 1            Infinity
Infinity / 8            Infinity
Infinity / -1          -Infinity
Infinity / -8          -Infinity
-Infinity / 1          -Infinity
-Infinity / 8          -Infinity
-Infinity / -1          Infinity
-Infinity / -8          Infinity
Infinity / Infinity     1
Infinity / -Infinity   -1
-Infinity / Infinity   -1
-Infinity / -Infinity   1
1 / 1                   1
1 / 8                   0.125
1 / Infinity            0
1 / -1                 -1
1 / -8                 -0.125
1 / -Infinity          -0
-1 / 1                 -1
-1 / 8                 -0.125
-1 / Infinity          -0
-1 / -1                 1
-1 / -8                 0.125
-1 / -Infinity          0
8 / 1                   8
8 / 8                   1
8 / Infinity            0
8 / -1                 -8
8 / -8                 -1
8 / -Infinity          -0
-8 / 1                 -8
-8 / 8                 -1
-8 / Infinity          -0
-8 / -1                 8
-8 / -8                 1
-8 / -Infinity          0
1 / 0.125               8
0.1 / 0.2               0.5
10 / -3                 -3.333333
1 / 0.0000000000000001  10000000000000000

Other:

This is , so shortest answer in bytes (per language) wins!

\$\endgroup\$
8
  • 1
    \$\begingroup\$ Since it sounds like input floats can be non-integer, it would be good to have some examples of that in the test cases. And I assume if we use floats, it wouldn't be held against us if the floats overflow to infinity when the output is be too large to represent? \$\endgroup\$
    – xnor
    Apr 9, 2021 at 18:23
  • 2
    \$\begingroup\$ @xnor I'll add some test cases for non-integers. Overflow and floating point errors are fine. \$\endgroup\$ Apr 9, 2021 at 18:24
  • 1
    \$\begingroup\$ Is [sign, positive float] a reasonable representation? \$\endgroup\$ Apr 9, 2021 at 18:34
  • 2
    \$\begingroup\$ @UnrelatedString I'm going to say no, sorry. It's probably only a few bytes to turn that into the required format in most languages though. \$\endgroup\$ Apr 9, 2021 at 18:36
  • 2
    \$\begingroup\$ @Wezl There's no "evaluate as ash" operator, but there is / which works fine :p \$\endgroup\$ Apr 9, 2021 at 18:48

8 Answers 8

30
\$\begingroup\$

Haskell, 35 bytes

x?y|isNaN$x/y=tanh x*tanh y|0<1=x/y

Try it online!

The relevant function is (?), which takes two Doubles as input and returns a Double as output.

How?

The hyperbolic tangent is an amazing function (two bytes shorter than signum!).

x tanh x
0.0 0.0
-0.0 -0.0
Infinity 1.0
-Infinity -1.0

Haskell, 30 29 bytes

x?y|x/y<=1/0=x/y|0<1=tanh$x*y

Try it online!

Using MarcMush's amazing trick, which relies on the well-known formula1 $$ \tanh(x\cdot y)=\tanh(x)\cdot\tanh(y). $$


1 I know, I know, maths.

\$\endgroup\$
3
  • 13
    \$\begingroup\$ Not gonna lie this is probably the first time I've ever seen someone use any of the hyperbolic trig functions in any programming language :p \$\endgroup\$ Apr 9, 2021 at 20:08
  • 2
    \$\begingroup\$ @Delfad0r impressive golf! But that equation at the bottom hurts my eyes! \$\endgroup\$
    – flawr
    Apr 10, 2021 at 21:06
  • 1
    \$\begingroup\$ @flawr It's maths 8) \$\endgroup\$
    – Delfad0r
    Apr 10, 2021 at 21:09
13
\$\begingroup\$

JavaScript (ES6), 45 bytes

Expects (a)(b), as Numbers. Returns a Number.

a=>b=>a/b||+(b?1/a?a/b:a*b>0||-1:1/a/b<0&&-0)

Try it online!

How?

Let \$\mathbb{R}^*\$ be \$\{x\in\mathbb{R}\mid x\neq0\}\$.

Direct answers when a/b is truthy

Whenever \$a/b\$ is neither NaN nor \$0\$, we know for sure that it is the expected answer. The cases that are covered that way are:

  • \$a\in\mathbb{R}^*\$, \$b\in\mathbb{R}^*\$ : standard division of non-zero, non-infinite floats
  • \$a\in\mathbb{R}^*\$, \$b=\pm0\$ : resulting in either \$+\infty\$ or \$-\infty\$
  • \$a=\pm\infty\$, \$b\in\mathbb{R}^*\$ : resulting in either \$+\infty\$ or \$-\infty\$
  • \$a=\pm\infty\$, \$b=\pm0\$ : resulting in either \$+\infty\$ or \$-\infty\$

Other cases

If \$a/b\$ is zero'ish, we test \$b\$:

  • If \$b\neq\pm0\$:
    • If \$1/a\neq\pm0\$, \$a/b\$ is also the correct answer, which is either \$0\$ or \$-0\$
    • If \$1/a=\pm0\$ (i.e. \$a=\pm\infty\$), we also have \$b=\pm\infty\$ and the answer is either \$1\$ or \$-1\$ depending on the sign of \$a\times b\$ (we do a*b>0||-1)
  • If \$b=\pm0\$, we also have \$a=\pm0\$ and the answer is either \$0\$ or \$-0\$ depending on the signs of \$a\$ and \$b\$ (we do 1/a/b<0&&-0)

JavaScript (ES6),  42  33 bytes

Using MarcMush's improvement of Delfad0r's excellent trick with tanh saves  3  12 bytes.

a=>b=>a/b<=1/0?a/b:Math.tanh(a*b)

Try it online!

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Actually MarcMush's improvement is even better, you can save two more bytes by using <=1/0 instead of (not) isNaN: a=>b=>a/b<=1/0?a/b:Math.tanh(a*b) \$\endgroup\$
    – Delfad0r
    Apr 10, 2021 at 10:03
12
\$\begingroup\$

Julia 0.7, 26 bytes

imaginary brownie points for using tanh instead of sign (thanks Delfad0r)

a$b=a/b<=Inf?a/b:tanh(a*b)

Try it online!

\$\endgroup\$
1
  • 4
    \$\begingroup\$ Wow that saves so many bytes, glad to have helped! \$\endgroup\$
    – Delfad0r
    Apr 10, 2021 at 6:46
9
\$\begingroup\$

R, 98 95 89 88 bytes

-6 bytes thanks to Giuseppe

function(x,y=abs(scan(t=x)))cat("-"[!!sd(grepl("-",x))],c(z<-y[1]/y[2],!!y)[1+is.na(z)])

Try it online!

Expects a vector of strings, as R cannot handle signed 0. Infinity will be input and output as Inf.

  • x contains the input as 2 strings, and y is the conversion to numeric in absolute value.
  • First, call grepl("-",x), giving a vector of two booleans. We need to output a - sign iff the two booleans are different, ie if the standard deviation is non-0.
  • Second, compute the division of the two values. R's division agrees with Ash's in most cases, but will give NaN for the two cases which are ambiguous: 0/0 and Inf/Inf. If the quotient is not NaN, we output it; otherwise, we compute the boolean !!y[1], convert to integer, and output that.

Note that we can use is.na instead of is.nan, as is.na(NaN) returns TRUE. (The two functions are nonetheless not equivalent; is.nan(NA) returns FALSE.)

\$\endgroup\$
5
  • \$\begingroup\$ 89 bytes. I had this for 95 before your latest golf. \$\endgroup\$
    – Giuseppe
    Apr 9, 2021 at 19:41
  • \$\begingroup\$ @Giuseppe Thanks! I was working on something similar but less efficient than your golf. (90 bytes) \$\endgroup\$ Apr 9, 2021 at 19:50
  • \$\begingroup\$ Gotta say, NaN^0==1 is quite surprising to me. 0^0==1 makes sense at least by convention... \$\endgroup\$
    – Giuseppe
    Apr 9, 2021 at 20:55
  • \$\begingroup\$ @Giuseppe Well, since ∀ x, x^0=1, it makes sense that the same would apply to NaN. \$\endgroup\$ Apr 9, 2021 at 21:33
  • \$\begingroup\$ I like the scan(t=) trick for converting text to numeric, and have accordingly stolen it. Thanks! \$\endgroup\$ Apr 9, 2021 at 22:31
7
\$\begingroup\$

Scratch, 310 bytes

Try it online!

In scratchblocks4:

when gf clicked
ask()and wait
set[N v]to(answer
ask()and wait
set[D v]to(answer
set[Q v]to((N)/(D
if<(Q)=[NaN]>then
if<(A)contains(0)?>then
set[Q v]to(0
else
set[Q v]to(1
end
end
if<<(join(N)(D))contains(-)?>and<not<<(N)contains(-)?>and<(D)contains(-)?>>>>then
if<(Q)contains(-)?>then
else
set[Q v]to(join(-)(Q

Alternatively, 37 blocks. No picture this time!

\$\endgroup\$
5
\$\begingroup\$

JavaScript (Node.js), 32 bytes

a=>b=>a/b+b/a?a/b:Math.sign(a*b)

Try it online!

Rule JavaScript (IEEE 754)
Zero divided by anything is 0 0/0 is NaN;
Same results for other values
Anything other than 0 divided by 0 is Infinity Same Results
Anything other than Infinity divided by Infinity is 0 Same Results
Infinity divided by anything other than Infinity is Infinity Same Results
Infinity divided by Infinity is 1 Infinity/Infinity=NaN
All other division works as normal Same Results

From above comparsion, we can see that, we only need to handle values when a/b is NaN. And whenever a/b is NaN, Math.sign(a*b) is what we want here.

So we use a/b+b/a to test NaN here. As long as a/b is not NaN, a/b, b/a have same signs. And adding them would always yield non-zero value. We know only 0, -0, NaN is falsy. And the value here is non-zero. So we can ensure the result is NaN if a/b+b/a is falsy.

\$\endgroup\$
2
  • \$\begingroup\$ Nice choice of language... \$\endgroup\$
    – Wasif
    Apr 10, 2021 at 9:43
  • \$\begingroup\$ @Wasif That actually how IEEE754 works, not specified to some languages. \$\endgroup\$
    – tsh
    Apr 10, 2021 at 9:58
4
\$\begingroup\$

C (gcc), 169 157 bytes

Thanks to @ceilingcat for the -12.

tanh seems like the way to go if you want to win this one, so I decided to try this without using any intrinsics, looking at the sign and exponents instead. NaN and denormals are not handled.

Annotated version:

*i,*j,w,x,t,u,v; char*z;
float f(a,b) float a,b; {
  i=&a; j=&b; // Get the integer representations of the floats
  w=*i*2; x=*j*2; // Move the exponents into the MSB of a copy
  t=*j; // Save the original value that will be clobbered
  u=3[z=&w]; v=3[z=&x]; // Get the exponents
  b=v?
      ~v? // x/!0
        ~u?
          j=0,a/b: // !INF/!(0,INF)=a/b (indicate normal division)
          1/0.: // INF/!(0,INF)=INF
        !~u: // INF/INF=1 or !INF/INF=0
      u? // x/0
        1/0.: // !0/0=INF
        0; // 0/0=0

  // Adjust the sign if normal division not used
  // (if one value is negative, it will flip the sign)
  j?*j^=(*i^t)&1<<31:0;
  a=b; // Store the result in the return
}
*i,*j,w,x,t,u,v;char*z;float f(a,b)float a,b;{i=&a;j=&b;w=*i*2;x=*j*2;t=*j;u=3[z=&w];v=3[z=&x];b=v?~v?~u?j=0,a/b:1/0.:!~u:u?1/0.:0;j?*j^=(*i^t)&1<<31:0;a=b;}

Try it online!

\$\endgroup\$
0
4
\$\begingroup\$

Jelly, 48 bytes

ẸṂ=?
ñç÷?
÷×¹?
®+©ṛ
”-eÇ
Ḋ⁸Ç?
ɠÇŒV
-1*®
7£2ŀ7£×¢

Takes input as newline-separated strings in STDIN, zero is 0.0, and infinity is inf.

Try it online!

How?

ẸṂ=?           - 1: λxλy: any(x, y) if x == y else min(x, y)
ñç÷?           - 2: λxλy: line3(x, y) if x÷y else line1(x, y)
÷×¹?           - 3: λxλy: x÷y if x else x×y
®+©ṛ           - 4: λx: add x to register; return x
”-eÇ           - 5: λx: link4("-" in x)
Ḋ⁸Ç?           - 6: λx: x[1:] if link5(x) else x
ɠÇŒV           - 7: eval(link6(read from stdin))
-1*®           - 8: (-1)^register
7£2ŀ7£×¢       - main: link2(link7, link7) * link8
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.