Comparar números de versión

26

Cuando publicamos algún software, le asignamos un número de versión. Y los usuarios pueden querer actualizar a la última versión de algún software. Entonces, es el momento de averiguar qué versión debería ser más nueva.

Entrada

Ingrese dos números de versión como cadenas.

En el contexto de este desafío, solo admitimos números de versión que son algunos dígitos unidos por puntos.

  • Un número de versión es una cadena que solo puede contener dígitos ( 0~ 9) y puntos ( .).
  • Los puntos no serían el primer / último carácter de un número de versión.
  • Debe haber algunos dígitos entre puntos. No pueden aparecer dos puntos continuamente.
  • Todos los números en un número de versión serían menores que 2 16 .

Salida

Compare los números de versión ingresados ​​y genere si el primero es mayor que / igual a / menor que el segundo. Puede elegir una de las siguientes presentaciones:

  • Use número positivo / cero / número negativo, mientras que cero significa igual;
  • Use tres valores distintos constantes;

Comparando

No es necesario que implemente el algoritmo descrito en esta sección. Su envío es válido siempre que resulte el mismo resultado con este algoritmo.

  • Los números de versión son algunos números decimales unidos por puntos. Primero dividimos los dos números de versión en matrices de números;
  • Rellenar el final de las matrices con ceros para que tengan la misma longitud;
  • Compare desde el primer elemento hasta el último:
    • Si los dos elementos de la matriz son diferentes, el número mayor significa un número de versión mayor
    • Si son iguales, continúe comparando los siguientes elementos;
    • Si todos los elementos de la matriz son iguales, las dos versiones son iguales.

Casos de prueba

version1  version2  result
2         1         >
1.0.0     1         =
1.0       1.0.0     =
1.2.42    1.2.41    >
1.1.56789 1.2.0     <
1.10      1.2       >
1.20      1.150     <
18.04     18.4      =
7.010     7.8       >
1.0.0.1.0 1.00.00.2 <
00.00.01  0.0.0.1   >
0.0.1     0.1       <
42.0      4.2.0     >
999.999   999.999.1 <
2018.08.1 2018.08   >
tsh
fuente
Relacionado , relacionado
FryAmTheEggman
.NET tiene un objeto Versión, pero no se admite un solo carácter :(
Brian J
@BrianJ y agregar '.0' cuesta a muchos personajes? :)
RobAu
Bueno, en realidad espera 2, 3 o 4 porciones. Por lo tanto, falla en el caso de prueba 1.0.0.1.0 (aunque intenté su idea inicialmente :))
Brian J
Creo que Windows tiene una función integrada que hará esto: StrCmpLogicalW
bace1000

Respuestas:

6

05AB1E (heredado) , 15 14 13 bytes

'.¡0ζε`.S}0K¬

Salidas -1 [] 1para < = >respectivamente.

-1 byte gracias a @Emigna .

Pruébelo en línea o verifique todos los casos de prueba .

Explicación:

'.¡              # Split on dots
                 #  i.e. ['1.0.1.1.0','1.00.2.0']
                 #   → [['1','0','1','1','0'],['1','00','2','0']]
   0ζ            # Zip, swapping rows and columns, using '0' as filler
                 #  i.e. [['1','0','1','1','0'],['1','00','2','0']]
                 #   → [['1','1'],['0','00'],['1','2'],['1','0'],['0','0']]
     ε   }       # Map each:
      `          #  Push both values to the stack
       .S        #  And calculate the signum (1 if a>b; -1 if a<b; 0 if a==b)
                 #   i.e. [['1','1'],['0','00'],['1','2'],['1','0'],['0','0']]
                 #    → [0,0,-1,1,0]
          0K     # Remove all zeros
                 #  i.e. [0,0,-1,1,0] → [-1,1]
            ¬    # Then take the head as result
                 #  i.e. [-1,1] → -1
Kevin Cruijssen
fuente
1
Puedes usar en 0Klugar de ʒĀ}.
Emigna
@Emigna Ah, por supuesto ... Gracias.
Kevin Cruijssen
5

R , 32 bytes

rank(numeric_version(scan(,"")))

Pruébalo en línea!

Usando un R incorporado

Salidas 1 2, 1.5 1.5, 2 1por menos, igual, mayor.


Mejor hasta ahora, sin construir:

R , 151 142 125 107 bytes

function(v,L=strsplit(v,'\\.'))Find(c,sign(Reduce('-',Map(as.double,Map(c,L,Map(rep,0,rev(lengths(L))))))))

Pruébalo en línea!

Código desenrollado con explicación:

function(v){             # character vector of 2 elements as function arg;
  L=strsplit(v,'\\.')    # obtain a list of two character vectors
                         # with the separated version numbers;
  R=rev(lengths(L))      # store in vector R the lengths of the 2 vectors and reverse it;
  M1=Map(rep,0,R)        # create a list of 2 vector containing zeros
                         # repeated R[1] and R[2] times;
  M2=Map(c,L,M1)         # append to the vectors in list L the zeros in M1;
  M3=Map(as.double,M2)   # convert the character vectors in M2 to double;
  w=sign(Reduce('-',M3)  # compute the sign of element by element difference M[[1]] - M[[2]]);
  Find(c,w)            # returns the first non zero element in w, if none return NULL;
}
# N.B. as.double is necessary because "0XX" is interpreted as octal by strtoi unless 
#      we use strtoi(x,10) which is exactly the same length of as.double(x)

Salidas -1, NULL, 1por menos, igual, mayor.


Concepto original, golfizado usando sapply, [<-y %*%:

R , 129 bytes

function(x,y=strsplit(x,"\\."),w=sign(sapply(y,function(x)strtoi("[<-"(rep(0,max(lengths(y))),seq(x),x),10))%*%c(1,-1)))w[!!w][1]

Pruébalo en línea!

Ahora tiene una lista de dos vectores de enteros de igual longitud. Calcule las diferencias por pares usando Reducey genere el primer elemento que no sea cero usando la pequeña y delicada w[!!w][1]forma al final.

Salidas -1, NA, 1por menos, igual, mayor.

ngm
fuente
¡Impresionante! Golf rápido: nueva línea adicional al final de su código; debe tener 150 bytes;)
JayCe
reducir el número de variables con nombre ... . Siento que hay una manera de hacerlo usando una matriz en lugar de listas, pero aún no he encontrado cómo hacerlo.
JayCe
1
Puede reducir esto a 100 bytes usando scan function(a,b,d=scan(t=a,se='.'),e=scan(t=b,se='.'),f=1:max(lengths(list(d,e))),g=d[f]-e[f])g[!!g][1](o 106 si desea devolver -1, NA, 1 no (negativo), NA, (positivo).
mnel
1
@mnel la solución de 100 bytes necesita un poco de trabajo. Falla en los últimos dos casos de prueba. El relleno tiene que ser 0y no (implícitamente) NA. He respondido un Wiki de la comunidad para que cualquiera que pueda solucionarlo pueda agregarlo.
ngm
1
@digEmAll jugó 4 bytes al calcular primero el signo y luego hacer Find(c,x). Creo que es un nuevo truco.
JayCe
4

APL (Dyalog Unicode) , 18 17 bytes

1 byte guardado gracias a @ Adám por usar en ⍤1lugar de ∘↑(...)¨y cambiando el formato de entrada de una matriz anidada a una matriz

(⍋-⍒)(⍎¨∊∘⎕D⊆⊢)⍤1

Pruébalo en línea!

Toma la entrada como una matriz de caracteres como el argumento correcto, donde cada cadena de versión está en su propia fila. Salidas ¯1 1, 0 0, 1 ¯1para <, =, >respectivamente.

(⍎¨∊∘⎕D⊆⊢)⍤1 en cada fila

  • ∊∘⎕D⊆⊢ agrupar todas las apariciones de dígitos, es decir, dividir en .

  • ⍎¨ y convertir cada una de estas ocurrencias en un número

convertir a una matriz, donde la primera entrada está en la fila superior y la segunda en la parte inferior, rellenando con 0s donde sea necesario

(⍋-⍒) y

  • - sustraer
    • los índices en las filas que los ordenarían en orden descendente
    • igual que la parte superior pero para orden ascendente
Kritixi Lithos
fuente
4

Perl 6 , 63 47 22 bytes

{"v$^a cmp v$^b".EVAL}

Pruébalo en línea!

Resulta que Perl 6 tiene un tipo de versión que se ajusta bastante a la descripción. Este es un bloque de código anónimo que toma una lista de dos cadenas de versión y devuelve More, Sameo Less.

Explicación:

{                    }  # Anonymous code block
 "             "        # Create a string of code
  v$^a cmp v$^b         # Comparing the two versions
                .EVAL   # And EVAL it

O, sin tipos incorporados para 47 bytes:

{first +*,[Z<=>] map *.split('.')[^@_.ords],@_}

Pruébalo en línea!

Bloque de código anónimo que toma dos cadenas y devuelve Moresi el segundo es mayor, Lesssi el segundo es más pequeño y Nilsi son iguales.

Explicación:

{                                             } # Anonymous code block
                 map *.split('.')          ,@_  # Split both strings by '.'
                                 [^@_.ords]     # Pad the lists by a lot
          [Z<=>]   # Zip the strings with the <=> operator
 first +*,  # Get the first value that when coerced to an int, is not 0
Jo King
fuente
3

Brachylog , 49 40 bytes

+0|{~c[H,".",T]hị;T|ị;0|0}ᵐz{h-0&t↰₀|h-}

... Sigue siendo bastante impresionante.

Espera una lista de dos cadenas. Usos positive number / zero / negative number como > / = / <.

Pruébalo en línea!

Explicación

Dividiendo las entradas

Dada una entrada que no unificar con [0, 0], tales como ["1.02.0", "1.2.0.1.0"], el siguiente salidas de segmento, por ejemplo, [[1, "02.0"], [1, "2.0.1.0"]].

                            # unify the input with...
+0                          # : a list whose sum = 0 (output is 0)
  |{                     }ᵐ # : OR a list that when mapped...
    ~c                      # : : if the input string unifies with a list of the form...
      [H,".",T]             # : : : e.g. "1.02.0", H = "1", T = "02.0"
               hị           # : : : coerce the head to an integer
                 ;T         # : : : append the string T
                            # : : : "1.02.0" -> [1, "02.0"]
                   |ị       # : : OR it unifies with an integer
                     ;0     # : : : append 0
                            # : : : "1" -> [1, 0]
                       |0   # : : OR it unifies with 0
                            # : : : 0 -> [0]

Comparar las entradas

Dado, por ejemplo, [[1, "02.0"], [1, "2.0.1.0"]]comprime las sublistas [[1, 1], ["02.0", "2.0.1.0"]]y compara los valores en el encabezado ( [1,1]). Recurre en la segunda sublista. Tenga en cuenta que el predicado zip zrecorre las listas más cortas, de modo que comprimir con [0,0]es equivalente a comprimir con [0], por lo tanto, el paso anterior se unifica 0con 0sin agregar más valores.

z             # zip the sublists
 {          } # unify the result (r) with...
  h           # : take the head of the result
   -          # : : subtract the second value from the first
    0         # : : if the difference unifies with 0...
     &t↰₀     # : : recur on the tail of r
         |h-  # : OR unify with the difference of the elements of the head
              # : (equivalent to returning early)
redundancia
fuente
3

JavaScript (ES6), 73 68 bytes

Guardado 5 bytes gracias a @redundancy

(a)(b)0

a=>b=>(a+[...b].fill`.`).split`.`.some((x,i)=>d=~b.split`.`[i]-~x)*d

Pruébalo en línea!

Arnauld
fuente
Agradable. Si he entendido correctamente, puede guardar bytes sustituyendo replacecon fill. Los operandos para -se intercambian ya que ambos deben ser obligados a un número. Pruébalo en línea!
redundancia
@redundancy ¡Buena idea! (Sin embargo, no estoy seguro si mi implementación es exactamente lo que tenía en mente.)
Arnauld
Supuse que su intención era agregar suficientes valores coercibles a 0, de modo que el mapeo sobre las subcadenas de aeventualmente recorra esos valores 0 si bcontiene más segmentos de números que a. Sucede que el método más corto para garantizar que sea así es dividirlo en una bcadena de longitud de '.' aprovechando la división existente aplicada a a.
redundancia
3

Java (JDK 10) , 201 96 89 bytes

java.util.Comparator.comparing(java.lang.module.ModuleDescriptor.Version::parse)::compare

Pruébalo en línea!

Devuelve un número negativo si la primera versión es más pequeña que la segunda, una positiva si la primera versión es mayor que la segunda y 0si son iguales.

Sí, eso es un trabajo pesado para "simplemente" llamar a un incorporado!

Créditos

Olivier Grégoire
fuente
1
Lo intenté, pero solo puedo eliminar tres bytes. 228 bytes
Kevin Cruijssen
1
Encontramos algo más: 217 bytes
Kevin Cruijssen
1
Probablemente sea eso. Ya lo intenté try-finallypara que el if-check pueda simplificarse; intentado volver dentro del bucle if t!=0; intentado usar Integery i.compare(i.valueOf(...),i.valueOf(...)); intenté usar genéricos como este <T>T[]g(T s){return(T[])(s+"").replaceAll("(\\.0+)*$","").split("\\.");}; etc. Todos son 2-6 bytes más largos. Si usted (o alguien más) encuentra algo más, hágamelo saber por favor. Curioso por saber qué. :)
Kevin Cruijssen
1
@KevinCruijssen No, no puedo porque "Todos los números en un número de versión serían menores que 2^16". Rangos cortos de - (2 ^ 15) a 2 ^ 15-1.
Olivier Grégoire
1
@KevinCruijssen ¡Podría eliminar 105 bytes! ¿Cómo? Bueno, encontré un incorporado;)
Olivier Grégoire
2

Python 2 , 87 bytes

lambda*p:cmp(*zip(*map(lambda x,y:(x or 0,y or 0),*[map(int,u.split('.'))for u in p])))

Pruébalo en línea!

Salidas -1,0,1 para <, =,>, respectivamente.

Chas Brown
fuente
2

Retina 0.8.2 , 54 bytes

\d+
$*
+`^(.)(.*=)\1
$2
(.*=|^=.*)1.*
<
.*1.*=.*
>
\.

Pruébalo en línea! El enlace incluye casos de prueba. Utiliza el valor del separador como salida de igualdad, por lo que, por conveniencia, el encabezado convierte el separador de entrada, =pero podría ser cualquier cosa que no esté dentro [.\d]. Explicación:

\d+
$*

Convierte a unario.

+`^(.)(.*=)\1
$2

Elimina repetidamente el primer carácter de cada lado hasta que difieran o un lado se agote. Esto es mucho más rápido que intentar unir prefijos, aunque posiblemente no sea más golfista. En este punto, las cadenas están en una de varias formas, que deben decodificarse para obtener un resultado de comparación.

  1. Si ninguna cadena contiene un, 1entonces el resultado es=
  2. Si la cadena izquierda comienza con a, 1entonces el resultado es>
  3. Si la cadena correcta comienza con a, 1entonces el resultado es<
  4. Si la cadena izquierda está vacía, el resultado es <
  5. En este punto, la cadena derecha está vacía, por lo que el resultado es >

Otra forma de pensar en esto es que si una cadena contiene a 1y la otra no comienza con a, 1entonces esa cadena es mayor, sin embargo, eso resulta ser un byte más largo.

(.*=|^=.*)1.*
<

Verifique el caso 3 o el caso 4 sin el caso 1.

.*1.*=.*
>

Si la cadena izquierda todavía contiene un a 1en este punto, entonces es mayor.

\.

De lo contrario, elimine cualquier sobrante de .s.

Firefox Browser Console REPL, 19 bytes

Services.vc.compare

Creo que esta función interna realiza la comparación requerida. Devuelve -1, 0 o 1.

Neil
fuente
1
Te sugiero que publiques el código Chrome de Firefox como otra respuesta ...
tsh
por cierto, no estoy seguro de cómo el código de Chrome de Firefox cuenta sus bytes. ¿Debería Cu.import("resource://gre/modules/Services.jsm");contarse?
tsh
1
@tsh Por eso agregué "REPL de la consola del navegador" ...
Neil
2

PHP , 38 bytes

<?=version_compare($argv[1],$argv[2]);

Salidas -1 → < | 0 → = | 1 → >

Pruébalo en línea!

Luis felipe De jesus Munoz
fuente
Creo que su presentación puede ser la función en sí misma
Jo King
1
Esto devuelve el resultado incorrecto para cualquier par de entradas que difieran solo en ceros finales, por ejemplo, 1.0.0y1
oktupol
2

C (gcc) ,  140  134 bytes

Este código genera un negativo, 0o un positivo para <, =o >respectivamente.

i;n;p;q;g(char*s){for(i=n=0;*s&&++n&&*s-46;i=i*10+*s++-48);i=i;}f(char*a,char*b){for(p=q=0;*a+*b&&p==q;b+=n)p=g(a),a+=n,q=g(b);a=p-q;}

Pruébalo en línea!

Ediciones:

  • ¡Guardado 6 bytes gracias a ceilingcat!
Annyo
fuente
El desafío dice: "Use tres valores distintos constantes"; Su código no devuelve constantes.
Olivier Grégoire
1
@Olivier Establece que puedo "Usar tres valores distintos constantes"; O "Use número positivo / cero / número negativo, mientras que cero significa igual";
Annyo
¡Mi error! Estás en lo correcto.
Olivier Grégoire
1

JavaScript (Node.js) , 105 88 80 bytes

-17 bytes de @redundancy. ¡Guauu!

-8 bytes eliminando Math.sign. Gracias @tsh

Devuelve un valor negativo, cero o positivo.

f=(a,b,r=/(\d*).?(.*)/)=>a+b&&+((a=r.exec(a))[1]-(b=r.exec(b))[1]||f(a[2],b[2]))

Pruébalo en línea!

Luis felipe De jesus Munoz
fuente
1
88 bytes utilizando execpara dividir cadenas. Pruébalo en línea!
redundancia
@redundancy Maldición, gracias! eso es un truco bastante fresco
Luis Felipe de Jesús Muñoz
Tal vez desee eliminar Math.sign para guardar algunos bytes cambiando a valores positivos / cero / negativos. Y tal vez se requiera un signo positivo.
tsh
1

Japt , 16 11 bytes

-5 bytes de @Shaggy

Salidas:

  • número negativo para <
  • ( nullo 0) para=
  • número positivo para >

N®q.Ãy_r-Ãf

Pruébalo en línea!

Luis felipe De jesus Munoz
fuente
¿Funcionaría esto ?
Shaggy
@Shaggy Sí, podría acortarse a 10 bytes con una salida negativa, nula o 0, positiva para < = >respectivamente, pero no sé si la entrada puede tomarse como una matriz
Luis felipe De jesus Munoz
0

Limpio , 116 111 bytes

import StdEnv,Text
?s=map toInt(split"."s)
$a b= @(?a)(?b)
@[h:t][u:v]|h==u= @t v=h-u
@l[]=sum l
@[]l= ~(sum l)

Pruébalo en línea!

Emite un número negativo cuando el primer argumento es menor que el segundo, cero cuando son equivalentes y un número positivo cuando es mayor que el segundo.

Οurous
fuente
0

Swift 4 , 155 bytes

Encabezado (sin contar: el código no es recursivo):

let f:(String,String)->Bool? = 

Código

{let x:(String)->[Int]={$0.split{$0=="."}.map{Int($0)!}.reversed().drop{$0==0}.reversed()},a=x($0),b=x($1)
return a==b ?nil:a.lexicographicallyPrecedes(b)}

Pruébalo en línea!

Explicaciones

  • Recortamos el final .0.
  • Comparamos componentes numéricamente.

Constantes devueltas

  • nulo para =
  • cierto para <
  • falso para>
Coeur
fuente
0

JavaScript 64 bytes

a=>b=>(e=i=>(g=v=>v.split`.`[i]||0)(a)-g(b)||!a[i]-1&&e(i+1))(0)

Pruébalo en línea!

Con comentarios:

a=>b=>(                            // Main function takes arguments like ("1.2.42")("1.2.41")
    e=i=>                          // e(i) compares the ith number, returns >0, <0 or =0.
        (   g=v=>v.split`.`[i]||0  // g() returns the ith string or 0
        )(a)                       // call g(a)
        -g(b)                      // subtracting g(b) from g(a) casts strings to integer
        ||                         // If they are not equal return result now
        !a[i]-1 &&                 // recursion limited to a.length, always sufficient
        e(i+1)                     // next i
    )(0)                           // Start with i = 0
James
fuente
0

Burlesque - 17 bytes

wd{'.;;)ri}m[^pcm


blsq ) "2018.08.1 2018.08"wd{'.;;)ri}m[^pcm
1
blsq ) "0.0.1 0.1"wd{'.;;)ri}m[^pcm
-1
blsq ) "1.1.56789 1.2.0"wd{'.;;)ri}m[^pcm
-1

Si desea salida en '> <=', agregue ?i"<=>"j!!Q.

mroman
fuente
0

Powershell, 88 bytes

Devuelve 0para igual, a positive integerpara mayor que o a negative integerpara menor que.

param($a,$b)+(($x=$a-split'\.')+($y=$b-split'\.')|%{$x[+$i]-$y[$i++]}|?{$_}|Select -f 1)

Menos guión de prueba de golf:

$f = {

param($a,$b)
$x=$a-split'\.'
$y=$b-split'\.'
$z=$x+$y|%{
    $x[+$i]-$y[$i++]
}|?{$_}|Select -first 1
+$z             # convert $null to 0

}

@(
    ,("2"         ,"1"         , 1)
    ,("1.0.0"     ,"1"         , 0)
    ,("1.0"       ,"1.0.0"     , 0)
    ,("1.2.42"    ,"1.2.41"    , 1)
    ,("1.1.56789" ,"1.2.0"     ,-1)
    ,("1.10"      ,"1.2"       , 1)
    ,("1.20"      ,"1.150"     ,-1)
    ,("18.04"     ,"18.4"      , 0)
    ,("7.010"     ,"7.8"       , 1)
    ,("1.0.0.1.0" ,"1.00.00.2" ,-1)
    ,("00.00.01"  ,"0.0.0.1"   , 1)
    ,("0.0.1"     ,"0.1"       ,-1)
    ,("42.0"      ,"4.2.0"     , 1)
    ,("999.999"   ,"999.999.1" ,-1)
    ,("2018.08.1" ,"2018.08"   , 1)
) | % {
    $v1,$v2,$expected = $_
    $result = &$f $v1 $v2
    "$([Math]::Sign($result)-eq$expected): $result"
}

Salida:

True: 1
True: 0
True: 0
True: 1
True: -1
True: 8
True: -130
True: 0
True: 2
True: -1
True: 1
True: -1
True: 38
True: -1
True: 1
mazzy
fuente
0

Dart , 277 231 bytes

F(s,{t}){t=s.split('.').map(int.parse).toList();while(t.last<1)t.removeLast();return t;}f(a,b,{d,e,f,g,h,i=0}){d=F(b);e=F(a);g=d.length;h=e.length;f=h>g?g:h;for(;i<f;i++)if(e[i]!=d[i])return e[i]>d[i]?1:-1;return h>g?1:(h<g?-1:0);}

Pruébalo en línea!

  • -44 bytes usando variables para almacenar longitud y usando ternary en bucle
  • -2 bytes eliminando los paréntesis for
Elcan
fuente
0

Swift 4 + Foundation , 160 bytes (142 + 18) , 155 bytes (142 + 13)

Importar (13 bytes, incluso ;para separar del código):

Esto importará Foundation, pero es 5 bytes más corto que import Foundation.

import UIKit;

Encabezado (sin contar: el código no es recursivo):

let f:(String,String)->ComparisonResult =

Código (142 bytes):

{var x={($0 as String).split{$0=="."}.count},a=$0,b=$1
while x(a)<x(b){a+=".0"}
while x(b)<x(a){b+=".0"}
return a.compare(b,options:.numeric)}

Pruébalo en línea!

Explicaciones

  1. Agregamos algunos .0 finales para el mismo número de componentes.
  2. Comparamos componentes numéricamente.

Constantes devueltas

  • ComparisonResult.orderedSame for =
  • ComparisonResult.orderedAscending para <
  • ComparisonResult.orderedDescending para>
Coeur
fuente
No estoy seguro si contamos la importdeclaración, por lo que publiqué una respuesta separada que no requiere Foundationy con un recuento de bytes entre 142 bytes (sin contar la importación) y 160 bytes (contando la importación).
Coeur
0

Zsh , 54 bytes

eval {autoload,}' is-at-least $'{1\ $2,2\ $1}';<<<$?;'

Pruébalo en línea! ¡Prueba una suite de prueba!

Esto evales para las siguientes ocho declaraciones:

autoload is-at-least $1 $2     # loads the "is-at-least" function
<<<$?                          # success, prints 0
autoload is-at-least $2 $1     # redundant
<<<$?                          # success, prints 0
is-at-least $1 $2              # exits 1 if $1 < $2
<<<$?
is-at-least $2 $1              # exits 1 if $2 < $1
<<<$?

Entonces los tres valores únicos son:

 cmp |  value
-----+------------------------------------------
  =  |  0<newline>0<newline>0<newline>0<newline>
  <  |  0<newline>0<newline>1<newline>0<newline>
  >  |  0<newline>0<newline>0<newline>1<newline>
Función Gamma
fuente