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 by0
isInfinity
- Anything other than
Infinity
divided byInfinity
is0
Infinity
divided by anything other thanInfinity
isInfinity
Infinity
divided byInfinity
is1
- 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 code-golf, so shortest answer in bytes (per language) wins!
8 Answers 8
Haskell, 35 bytes
x?y|isNaN$x/y=tanh x*tanh y|0<1=x/y
The relevant function is (?)
, which takes two Double
s 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
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.
-
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\$2021年04月09日 20:08:17 +00:00Commented Apr 9, 2021 at 20:08
-
2\$\begingroup\$ @Delfad0r impressive golf! But that equation at the bottom hurts my eyes! \$\endgroup\$flawr– flawr2021年04月10日 21:06:39 +00:00Commented Apr 10, 2021 at 21:06
-
1\$\begingroup\$ @flawr It's maths 8) \$\endgroup\$Delfad0r– Delfad0r2021年04月10日 21:09:00 +00:00Commented Apr 10, 2021 at 21:09
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)
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)
-
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– Delfad0r2021年04月10日 10:03:14 +00:00Commented Apr 10, 2021 at 10:03
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)
-
4\$\begingroup\$ Wow that saves so many bytes, glad to have helped! \$\endgroup\$Delfad0r– Delfad0r2021年04月10日 06:46:02 +00:00Commented Apr 10, 2021 at 6:46
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)])
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, andy
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
andInf/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
.)
-
-
\$\begingroup\$ @Giuseppe Thanks! I was working on something similar but less efficient than your golf. (90 bytes) \$\endgroup\$Robin Ryder– Robin Ryder2021年04月09日 19:50:45 +00:00Commented 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– Giuseppe2021年04月09日 20:55:07 +00:00Commented 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\$Robin Ryder– Robin Ryder2021年04月09日 21:33:11 +00:00Commented 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\$Dominic van Essen– Dominic van Essen2021年04月09日 22:31:55 +00:00Commented Apr 9, 2021 at 22:31
Scratch, 310 bytes
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!
JavaScript (Node.js), 32 bytes
a=>b=>a/b+b/a?a/b:Math.sign(a*b)
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.
-
\$\begingroup\$ Nice choice of language... \$\endgroup\$wasif– wasif2021年04月10日 09:43:19 +00:00Commented Apr 10, 2021 at 9:43
-
\$\begingroup\$ @Wasif That actually how IEEE754 works, not specified to some languages. \$\endgroup\$tsh– tsh2021年04月10日 09:58:40 +00:00Commented Apr 10, 2021 at 9:58
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;}
Jelly, 48 bytes
ẸṂ=×ばつ1?
®+©ṛ
"-eÇ
Ḋ8Ç?
ɠÇŒV
-1*®
72ドルl×ばつ¢
Takes input as newline-separated strings in STDIN, zero is 0.0
, and infinity is inf
.
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)×ばつ1? - 3: λxλy: x÷y if x else ×ばつy
®+©ṛ - 4: λx: add x to register; return x
"-eÇ - 5: λx: link4("-" in x)
Ḋ8Ç? - 6: λx: x[1:] if link5(x) else x
ɠÇŒV - 7: eval(link6(read from stdin))
-1*® - 8: (-1)^register
72ドルl×ばつ¢ - main: link2(link7, link7) * link8
Explore related questions
See similar questions with these tags.
[sign, positive float]
a reasonable representation? \$\endgroup\$/
which works fine :p \$\endgroup\$