# Zero(π) and one(π) are false and true?

**URL:** <https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802>\
**Category:** New to Julia\
**Tags:** numbers\
**Created:** [September 26, 2022, 8:10am UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802 "2022-09-26T08:10:46Z")\
**Posts on this page:** 11\
**Page:** 2

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [September 26, 2022, 12:46pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/21 "2022-09-26T12:46:00Z")

</div>

That can also be argued, I just think all numeric types need to have `one` and `zero` defined, at least a lot of code relies on that to be generic, now if it’s misleading then maybe you don’t want it defined… [Is it helpful, or hurtful, to have it, and then approximate? I’m not sure what would happen with just one and zero dropped and irrationals otherwise kept, more or less complaining?] I just meant in the math sense 1 (the returned type sort of) is that identity. Of course the functions are all about types, either you would simply write 1 and 0…

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [September 26, 2022, 1:08pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/22 "2022-09-26T13:08:25Z")

</div>

> [@nsajko](#):
>
> make each irrational constant a function that takes a `<:Real` type.

Yes, in retrospect that would have been much better. Cf

> <https://github.com/JuliaLang/julia/issues/37977>
>
> Based on the discussion in #37931, I have found that \`pi == one(pi)\*pi\` is broke…n. However, it should hold according to the documentation of \`one()\` function:
> 
> \`\`\` julia
> one(x)
> one(T::type)
> Return a multiplicative identity for \`x\`: a value such that
> \`one(x)\*x == x\*one(x) == x\`. Alternatively \`one(T)\` can
> take a type \`T\`, in which case \`one\` returns a multiplicative
> identity for any \`x\` of type \`T\`.
> 
> If possible, \`one(x)\` returns a value of the same type as \`x\`,
> and \`one(T)\` returns a value of type \`T\`. However, this may
> not be the case for types representing dimensionful quantities
> (e.g. time in days), since the multiplicative
> identity must be dimensionless. In that case, \`one(x)\`
> should return an identity value of the same precision
> (and shape, for matrices) as \`x\`.
> ...
> \`\`\`
> 
> Don't know if you prefer fixing the implementation or just updating the documentation to make it consistent. Notice that since \`one(pi)\` already returns \`true\`, it would be possible to make \`true \* pi === pi\`.

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [September 26, 2022, 6:42pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/23 "2022-09-26T18:42:42Z")

</div>

I would argue that, since `zero` and `one` is apparently defined as being the additive and multiplicative identity, having `one(π) * π != π` is quite clearly a bug.  
The alternative is to either define a `one` or `zero` type for irrationals, or preferrably, to not have added this buggy definition in the first place.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [September 26, 2022, 8:09pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/24 "2022-09-26T20:09:22Z")

</div>

The problem here seems to be the definition of `!=` or `==` which is not the same as the mathematical concept of `=`.

We also have the following result due to floating point arithmetic. Due to finite precision, we know the underlying numerical system has imperfections.

```julia
julia> 0.1 + 0.2 == 0.3
false

julia> 0.3 - 0.1 - 0.2
-2.7755575615628914e-17

```

If we are trying to apply mathematical concepts, then often ` ≈`, `\approx[tab]`, is probably a better suited for that purpose.

```julia
julia> 0.1 + 0.2 ≈ 0.3
true

julia> one(π) * π ≈ π
true

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [September 26, 2022, 8:23pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/25 "2022-09-26T20:23:22Z")

</div>

> [@mkitti](#):
>
> ```julia
> julia> 0.1 + 0.2 == 0.3
> false
> 
> ```

I don’t think this is the same. 0.3 isn’t _defined_ as “the floating point sum of 0.1 and 0.2”. It just happens that they are equal in some number systems (but not `Float64`), and has many other properties as well.

`one`, on the other hand has only one primary property, which is identical to its definition, and that is

```julia
one(x) * x == x

```

When this fails, it’s seems a bit pointless.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [September 26, 2022, 8:36pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/26 "2022-09-26T20:36:14Z")

</div>

> [@DNF](#):
>
> ```julia
> one(x) * x == x
> 
> ```
> 
> When this fails, it’s seems a bit pointless.

Why do we even need `one(x)` to begin with? Why not just `one * x`?

```julia
julia> import Base.*

julia> one::typeof(one) * x = x
* (generic function with 338 methods)

julia> one * π
π = 3.1415926535897...

```

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [September 26, 2022, 10:16pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/27 "2022-09-26T22:16:41Z")

</div>

> [@mkitti](#):
>
> Why do we even need `one(x)` to begin with?

It took my a while seeing you were defining a function… with:

```julia
one::typeof(one) * x = x # seems you don't need: import Base.*

julia> π * one
ERROR: MethodError: no method matching *(::Irrational{:π}, ::typeof(one))

```

so as a replacement for 1-ary function, since you define a binary operator/function, you would also need just in case someone rather does above for it to work:

```julia
x * one::typeof(one) = x # or this way, still looks odd: *(x, one::typeof(one)) = x

```

It’s too bad you can’t define:

```julia
julia> 1::typeof(one) * x = x
ERROR: syntax: "1" is not a valid function argument name around REPL[575]:1

```

except that’s in a sense possible, already such done for some literal powers, and you could define 2π that way, and 1π just in case someone would type that in, and I guess -π, -2π etc.

---

<div class="post-metadata">

**Author:** ![benninkrs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/benninkrs/32/3191_2.png) [@benninkrs](https://discourse.julialang.org/u/benninkrs)\
**Post date:** [September 26, 2022, 10:24pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/28 "2022-09-26T22:24:52Z")

</div>

A couple years ago I [suggested](https://github.com/JuliaLang/julia/issues/36103#issuecomment-639562896) something similar, namely singleton types for the concepts of additive and multiplicative identities. It didn’t gain any traction but I still think it would be a good idea when suitable concrete types aren’t known or don’t exist.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [September 26, 2022, 10:25pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/29 "2022-09-26T22:25:34Z")

</div>

> [@mkitti](#):
>
> Why do we even need `one(x)` to begin with?

It’s used also for things like initializing arrays.

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [September 26, 2022, 10:52pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/30 "2022-09-26T22:52:56Z")

</div>

> [@mkitti](#):
>
> Why do we even need `one(x)` to begin with? Why not just `one * x`?

[InitialValues.jl](https://juliafolds.github.io/InitialValues.jl/dev/) takes only the function, not the operand type. eg

```julia
julia> InitialValue(*) * 3
3

```

---

<div class="post-metadata">

**Author:** ![moble](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/moble/32/23535_2.png) [@moble](https://discourse.julialang.org/u/moble)\
**Post date:** [September 29, 2022, 1:40pm UTC](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802/31 "2022-09-29T13:40:24Z")

</div>

You can see something similar with the unit imaginary `im`. It’s [defined as](https://github.com/JuliaLang/julia/blob/9fd408723aab0974f399b8ffc952af4b4d20b6f7/base/complex.jl#L36) `Complex(false, true)`, and we have

```julia
julia> zero(im)
Complex(false,false)

julia> one(im)
Complex(true,false)

```

This works nicely because `Complex` is a parametric type, so if you multiply `im` by some number of your favorite type `T`, you’ll get a `Complex{T}` because `Bool` multiplied by `T` generally results in `T`:

```julia
julia> typeof(2im)
Complex{Int64}

julia> typeof(2.0im)
ComplexF64 (alias for Complex{Float64})

julia> typeof(BigFloat(2)im)
Complex{BigFloat}

```

I’ve never encountered any loss of precision or unexpected type problems with `Complex`.

The behavior of `Irrational`, on the other hand, is not so nice. Specifically,

```julia
julia> typeof(2π)
Float64

```

This is especially troublesome when you have a fancy mathematical formula that you want to work with another number type. Suppose we define

```julia
function f(x)
    2π * x
end

```

Well, `f(BigFloat(2))` returns a `BigFloat`, as expected. But the _accuracy_ of this result is only about `5e-16` — because `2π` is a `Float64`.

```julia
julia> f(BigFloat(2)) ≈ 4*BigFloat(π)
false

julia> f(BigFloat(2)) - 4*BigFloat(π)
-4.898587[...]e-16

```

This is very sneaky and very annoying if you’re trying to work with different number types.

What I end up doing is first converting `π` to the type of `x`:

```julia
function g(x)
    let π=oftype(x, π)
        2π * x
    end
end

```

With this modification, we have exact agreement:

```julia
julia> g(BigFloat(2)) - 4*BigFloat(π)
0.0

```

This works with all the usual float types and [now with `Symbolics.jl`](https://github.com/JuliaSymbolics/Symbolics.jl/pull/638). It doesn’t work with integer types; if needed, you could use something like `let π = float(typeof(x))(π)` instead. Again, this is annoying and inelegant, but at least it’s a workaround when you know that there’s something to work around.

[Previous page](https://discourse.julialang.org/t/zero-and-one-are-false-and-true/87802.md?page=1)
