Можно ли сказать Юлии интерпретировать 0.0 / 0.0 как 1? - PullRequest
8 голосов
/ 20 сентября 2019

Я имею дело с некоторыми функциями Float64, которые внутри своего тела вычисляют некоторые дроби, которые могут принимать значение 0.0 / 0.0.В этом случае это значение следует интерпретировать как 1,0.Можно ли сделать это автоматически и избежать кодирования патологических случаев?

1 Ответ

10 голосов
/ 20 сентября 2019

Да, довольно просто сделать это безопасным способом, который не нарушает код Джулии или других людей.

Один из способов добиться этого - либо внутри вашего модуля, либо в REPL, перед тем, как выкогда-либо явно использовать функцию / [1], просто напишите

/(args...) = Base.:(/)(args...)

function /(x::Float64, y::Float64)
    if x == 0.0 && y == 0.0
        1.0
    else
        Base.:(/)(x, y)
    end 
end

В ответ:

julia> 1 / 2
0.5

julia> 10.0 / 0.0
Inf

julia> 0.0 / 0.0
1.0

Что это делает тени встроенный/ и заменяет ее своей собственной версией, которая отличается от встроенной.Это затенение локально только для текущего модуля, в котором вы находитесь, и не просочится наружу, если кто-то явно не попросит вашу версию.

Другой (возможно, предпочтительный) вариант - создать новую функцию разделения инфиксов с помощью операторов Юникода.,Вот пример:

function /̂(x, y) # /̂ is typed /\hat<TAB> at the REPL
    if x == 0 && y == 0
        one(promote_type(typeof(x), typeof(y)))
    else
        x / y
    end 
end

На REPL:

julia> 0 /̂ 0.0
1.0

julia> 1 /̂ 2
0.5

julia> 0 / 0
NaN

Это работает, потому что каждый раз, когда вы применяете модификатор юникода, такой как \hat, или верхний индекс, или что-то еще к символу функции инфикса (как / или * или что-то еще) вы создаете новый инфиксный оператор с таким же приоритетом.Это хорошо, потому что мы можем сохранить старое определение / и у нашего оператора деления есть визуальный маркер, что происходит что-то необычное.

Наслаждайтесь!


[1]: Функции из Base фактически вытягиваются в ваше пространство имен при первом их использовании, поэтому, если вы еще не использовали / в своей текущей области видимости, вы можете затенять его.В противном случае вам нужно будет ввести новую область видимости через блок let, и там будет затенена только /.

...