Ricerca…


Sintassi

  • x <y # se x è strettamente inferiore a y
  • x> y # se x è strettamente maggiore di y
  • x == y # se x è uguale a y
  • x === y # in alternativa x ≡ y , se x è uguale a y
  • x ≤ y # in alternativa x <= y , se x è minore o uguale a y
  • x ≥ y # in alternativa x >= y , se x è maggiore o uguale a y
  • x ≠ y # in alternativa x != y , se x non è uguale a y
  • x ≈ y # se x è approssimativamente uguale a y

Osservazioni

Stai attento a lanciare i segni di confronto in giro. Julia definisce molte funzioni di confronto per impostazione predefinita senza definire la corrispondente versione capovolta. Ad esempio, si può correre

julia> Set(1:3) ⊆ Set(0:5)
true

ma non funziona

julia> Set(0:5) ⊇ Set(1:3)
ERROR: UndefVarError: ⊇ not defined

Confronti concatenati

Gli operatori di confronto multipli utilizzati insieme sono concatenati, come se fossero collegati tramite l' operatore && . Questo può essere utile per catene di confronto leggibili e matematicamente concise, come

# same as 0 < i && i <= length(A)
isinbounds(A, i)       = 0 < i ≤ length(A)

# same as Set() != x && issubset(x, y)
isnonemptysubset(x, y) = Set() ≠ x ⊆ y

Tuttavia, c'è una differenza importante tra a > b > c e a > b && b > c ; nel secondo caso, il termine b viene valutato due volte. Questo non importa molto per i semplici simboli vecchi, ma potrebbe importare se i termini stessi hanno effetti collaterali. Per esempio,

julia> f(x) = (println(x); 2)
f (generic function with 1 method)

julia> 3 > f("test") > 1
test
true

julia> 3 > f("test") && f("test") > 1
test
test
true

Diamo un'occhiata più approfondita ai confronti concatenati e al loro funzionamento, osservando come vengono analizzati e ridotti in espressioni . Innanzitutto, considera il semplice confronto, che possiamo vedere solo una semplice chiamata di funzione vecchia:

julia> dump(:(a > b))
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol >
    2: Symbol a
    3: Symbol b
  typ: Any

Ora se eseguiamo il paragone, notiamo che l'analisi è cambiata:

julia> dump(:(a > b >= c))
Expr
  head: Symbol comparison
  args: Array{Any}((5,))
    1: Symbol a
    2: Symbol >
    3: Symbol b
    4: Symbol >=
    5: Symbol c
  typ: Any

Dopo l'analisi, l'espressione viene quindi abbassata nella sua forma finale:

julia> expand(:(a > b >= c))
:(begin 
        unless a > b goto 3
        return b >= c
        3: 
        return false
    end)

e notiamo infatti che questo è lo stesso di a > b && b >= c :

julia> expand(:(a > b && b >= c))
:(begin 
        unless a > b goto 3
        return b >= c
        3: 
        return false
    end)

Numeri ordinali

Vedremo come implementare confronti personalizzati implementando un tipo personalizzato, numeri ordinali . Per semplificare l'implementazione, ci concentreremo su un piccolo sottoinsieme di questi numeri: tutti i numeri ordinali fino a ma non incluso ε₀. La nostra implementazione è focalizzata sulla semplicità, non sulla velocità; tuttavia, anche l'implementazione non è lenta.

Memorizziamo numeri ordinali secondo la loro forma normale di Cantor . Poiché l'aritmetica ordinale non è commutativa, adotteremo la convenzione comune di memorizzare prima i termini più significativi.

immutable OrdinalNumber <: Number
    βs::Vector{OrdinalNumber}
    cs::Vector{Int}
end

Poiché la forma normale di Cantor è unica, possiamo testare l'uguaglianza semplicemente attraverso l'uguaglianza ricorsiva:

0.5.0

Nella versione v0.5, c'è una sintassi molto bella per farlo in modo compatto:

import Base: ==
α::OrdinalNumber == β::OrdinalNumber = α.βs == β.βs && α.cs == β.cs
0.5.0

Altrimenti, definire la funzione come più tipica:

import Base: ==
==(α::OrdinalNumber, β::OrdinalNumber) = α.βs == β.βs && α.cs == β.cs

Per completare il nostro ordine, poiché questo tipo ha un ordine totale, dovremmo sovraccaricare la funzione isless :

import Base: isless
function isless(α::OrdinalNumber, β::OrdinalNumber)
    for i in 1:min(length(α.cs), length(β.cs))
        if α.βs[i] < β.βs[i]
            return true
        elseif α.βs[i] == β.βs[i] && α.cs[i] < β.cs[i]
            return true
        end
    end
    return length(α.cs) < length(β.cs)
end

Per testare il nostro ordine, possiamo creare alcuni metodi per creare numeri ordinali. Zero, ovviamente, si ottiene non avendo termini nella forma normale di Cantor:

const ORDINAL_ZERO = OrdinalNumber([], [])
Base.zero(::Type{OrdinalNumber}) = ORDINAL_ZERO

Possiamo definire un expω per calcolare ω^α , e usarlo per calcolare 1 e ω:

expω(α) = OrdinalNumber([α], [1])
const ORDINAL_ONE = expω(ORDINAL_ZERO)
Base.one(::Type{OrdinalNumber}) = ORDINAL_ONE
const ω = expω(ORDINAL_ONE)

Ora abbiamo una funzione di ordinamento completamente funzionale sui numeri ordinali:

julia> ORDINAL_ZERO < ORDINAL_ONE < ω < expω(ω)
true

julia> ORDINAL_ONE > ORDINAL_ZERO
true

julia> sort([ORDINAL_ONE, ω, expω(ω), ORDINAL_ZERO])

4-element Array{OrdinalNumber,1}:
                                                                                                       OrdinalNumber(OrdinalNumber[],Int64[])
                                                                     OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[],Int64[])],[1])
                                   OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[],Int64[])],[1])],[1])
 OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[],Int64[])],[1])],[1])],[1])

Nell'ultimo esempio, vediamo che la stampa dei numeri ordinali potrebbe essere migliore, ma il risultato è come previsto.

Operatori standard

Julia supporta un insieme molto grande di operatori di confronto. Questi includono

  1. Tutte le seguenti sequenze Unicode: > < >= ≥ <= ≤ == === ≡ != ≠ !== ≢ ∈ ∉ ∋ ∌ ⊆ ⊈ ⊂ ⊄ ⊊ ∝ ∊ ∍ ∥ ∦ ∷ ∺ ∻ ∽ ∾ ≁ ≃ ≄ ≅ ≆ ≇ ≈ ≉ ≊ ≋ ≌ ≍ ≎ ≐ ≑ ≒ ≓ ≔ ≕ ≖ ≗ ≘ ≙ ≚ ≛ ≜ ≝ ≞ ≟ ≣ ≦ ≧ ≨ ≩ ≪ ≫ ≬ ≭ ≮ ≯ ≰ ≱ ≲ ≳ ≴ ≵ ≶ ≷ ≸ ≹ ≺ ≻ ≼ ≽ ≾ ≿ ⊀ ⊁ ⊃ ⊅ ⊇ ⊉ ⊋ ⊏ ⊐ ⊑ ⊒ ⊜ ⊩ ⊬ ⊮ ⊰ ⊱ ⊲ ⊳ ⊴ ⊵ ⊶ ⊷ ⋍ ⋐ ⋑ ⋕ ⋖ ⋗ ⋘ ⋙ ⋚ ⋛ ⋜ ⋝ ⋞ ⋟ ⋠ ⋡ ⋢ ⋣ ⋤ ⋥ ⋦ ⋧ ⋨ ⋩ ⋪ ⋫ ⋬ ⋭ ⋲ ⋳ ⋴ ⋵ ⋶ ⋷ ⋸ ⋹ ⋺ ⋻ ⋼ ⋽ ⋾ ⋿ ⟈ ⟉ ⟒ ⦷ ⧀ ⧁ ⧡ ⧣ ⧤ ⧥ ⩦ ⩧ ⩪ ⩫ ⩬ ⩭ ⩮ ⩯ ⩰ ⩱ ⩲ ⩳ ⩴ ⩵ ⩶ ⩷ ⩸ ⩹ ⩺ ⩻ ⩼ ⩽ ⩾ ⩿ ⪀ ⪁ ⪂ ⪃ ⪄ ⪅ ⪆ ⪇ ⪈ ⪉ ⪊ ⪋ ⪌ ⪍ ⪎ ⪏ ⪐ ⪑ ⪒ ⪓ ⪔ ⪕ ⪖ ⪗ ⪘ ⪙ ⪚ ⪛ ⪜ ⪝ ⪞ ⪟ ⪠ ⪡ ⪢ ⪣ ⪤ ⪥ ⪦ ⪧ ⪨ ⪩ ⪪ ⪫ ⪬ ⪭ ⪮ ⪯ ⪰ ⪱ ⪲ ⪳ ⪴ ⪵ ⪶ ⪷ ⪸ ⪹ ⪺ ⪻ ⪼ ⪽ ⪾ ⪿ ⫀ ⫁ ⫂ ⫃ ⫄ ⫅ ⫆ ⫇ ⫈ ⫉ ⫊ ⫋ ⫌ ⫍ ⫎ ⫏ ⫐ ⫑ ⫒ ⫓ ⫔ ⫕ ⫖ ⫗ ⫘ ⫙ ⫷ ⫸ ⫹ ⫺ ⊢ ⊣ ;
  2. Tutti i simboli nel punto 1, preceduti da un punto ( . ) Da rendere elementwise;
  3. Gli operatori <: , >: , .! e in , che non possono essere preceduti da un punto ( . ).

Non tutti hanno una definizione nella libreria Base standard. Tuttavia, sono disponibili per altri pacchetti da definire e utilizzare come appropriato.

Nell'uso quotidiano, la maggior parte di questi operatori di confronto non sono rilevanti. I più comuni utilizzati sono le funzioni matematiche standard per l'ordinazione; vedere la sezione Sintassi per un elenco.

Come la maggior parte degli altri operatori di Julia, gli operatori di confronto sono funzioni e possono essere chiamati come funzioni. Ad esempio, (<)(1, 2) è identico nel significato a 1 < 2 .

Usando ==, === e isequal

Esistono tre operatori di uguaglianza: == , === e isequal . (L'ultimo non è realmente un operatore, ma è una funzione e tutti gli operatori sono funzioni.)

Quando usare ==

== è l'uguaglianza di valore . Restituisce true quando due oggetti rappresentano, nel loro stato attuale, lo stesso valore.

Ad esempio, è ovvio che

julia> 1 == 1
true

ma inoltre

julia> 1 == 1.0
true

julia> 1 == 1.0 + 0.0im
true

julia> 1 == 1//1
true

I lati di destra di ogni uguaglianza sopra sono di un tipo diverso, ma rappresentano sempre lo stesso valore.

Per oggetti mutabili, come gli array , == confronta il loro valore attuale.

julia> A = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

julia> B = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

julia> C = [1, 3, 2]
3-element Array{Int64,1}:
 1
 3
 2

julia> A == B
true

julia> A == C
false

julia> A[2], A[3] = A[3], A[2]  # swap 2nd and 3rd elements of A
(3,2)

julia> A
3-element Array{Int64,1}:
 1
 3
 2

julia> A == B
false

julia> A == C
true

Il più delle volte, == è la scelta giusta.

Quando usare ===

=== è un'operazione molto più rigida di == . Invece dell'uguaglianza di valore, misura l'eguaglianza. Due oggetti sono eguali se non possono essere distinti l'uno dall'altro dal programma stesso. Così abbiamo

julia> 1 === 1
true

in quanto non c'è modo di distinguere 1 dall'altra 1 . Ma

julia> 1 === 1.0
false

perché sebbene 1 e 1.0 abbiano lo stesso valore, sono di tipi diversi e quindi il programma può distinguerli.

Inoltre,

julia> A = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

julia> B = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

julia> A === B
false

julia> A === A
true

che a prima vista può sembrare sorprendente! Come potrebbe il programma distinguere tra i due vettori A e B ? Poiché i vettori sono mutabili, potrebbe modificare A e quindi si comporterebbe diversamente da B Ma non importa come modifica A , A si comporterà sempre come A stesso. Quindi A è egale ad A , ma non egale a B

Continuando su questa linea, osserva

julia> C = A
3-element Array{Int64,1}:
 1
 2
 3

julia> A === C
true

Assegnando A a C , diciamo che C ha alias A Cioè, è diventato solo un altro nome per A Anche le modifiche apportate ad A saranno osservate da C Pertanto, non c'è modo di dire la differenza tra A e C , quindi sono uguali.

Quando usare isequal

La differenza tra == e isequal è molto sottile. La più grande differenza riguarda la modalità di gestione dei numeri in virgola mobile:

julia> NaN == NaN
false

Questo risultato, forse sorprendente, è definito dallo standard IEEE per i tipi a virgola mobile (IEEE-754). Ma questo non è utile in alcuni casi, come l'ordinamento. isequal è fornito per quei casi:

julia> isequal(NaN, NaN)
true

Dall'altra parte dello spettro, == tratta lo zero negativo IEEE e lo zero positivo come lo stesso valore (anche come specificato da IEEE-754). Questi valori hanno rappresentazioni distinte in memoria, tuttavia.

julia> 0.0
0.0

julia> -0.0
-0.0

julia> 0.0 == -0.0
true

Ancora una volta per scopi di smistamento, isequal distingue tra loro.

julia> isequal(0.0, -0.0)
false


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow