Me pregunto si hay formas no triviales de encontrar el signo del número ( función signum ).
Pueden ser soluciones más cortas / rápidas / más elegantes que la obvia
var sign = number > 0 ? 1 : number < 0 ? -1 : 0;
¡Respuesta corta!
Use esto y estará seguro y rápido (fuente: moz )
if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };
Es posible que desee ver el violín de comparación de rendimiento y coerción de tipos
Ha pasado mucho tiempo. Además es principalmente por razones históricas.
Resultados
Por ahora tenemos estas soluciones:
1. Obvio y rápido
function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }
1.1. Modificación de kbec : un tipo de lanzamiento menos, más eficaz , más corto [más rápido]
function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }
precaución: sign("0") -> 1
2. Elegante, corto, no tan rápido [más lento]
function sign(x) { return x && x / Math.abs(x); }
PRECAUCIÓN: sign(+-Infinity) -> NaN
,sign("0") -> NaN
A partir de Infinity
un número legal en JS, esta solución no parece del todo correcta.
3. El arte ... pero muy lento [más lento]
function sign(x) { return (x > 0) - (x < 0); }
4. Usando bit-shift
rápido, perosign(-Infinity) -> 0
function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }
5. Tipo seguro [megafast]
! Parece que los navegadores (especialmente Chrome's v8) hacen algunas optimizaciones mágicas y esta solución resulta ser mucho más eficiente que otras, incluso que (1.1) a pesar de que contiene 2 operaciones adicionales y lógicamente nunca puede ser más rápida.
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
Herramientas
¡Las mejoras son bienvenidas!
[Offtopic] Respuesta aceptada
Andrey Tarantsov - +100 por el arte, pero lamentablemente es aproximadamente 5 veces más lento que el enfoque obvio
Frédéric Hamidi : de alguna manera, la respuesta más votada (por el momento) y es un poco genial, pero definitivamente no es así como se deben hacer las cosas, en mi humilde opinión. Además, no maneja correctamente los números Infinity, que también son números, ya sabes.
kbec - es una mejora de la solución obvia. No es tan revolucionario, pero en conjunto considero que este enfoque es el mejor. Vota por él :)
fuente
0
es un caso especialtest everything
versión, Safe se negará a probar los valores especiales, ¡así que será más rápido! Intente ejecutar laonly integers
prueba en su lugar. Además, JSPerf solo está haciendo su trabajo, no es cuestión de que le guste. :)typeof x === "number"
da algo de magia al rendimiento. Por favor, haga más ejecuciones, especialmente FF, Opera e IE para que quede claro.Math.sign()
(0 === 0, no tan rápido como "Seguro") que apareció en FF25 y está por venir en Chrome.Respuestas:
Versión más elegante de solución rápida:
fuente
var sign = (number)? ((number < 0)? -1 : 1 ) : 0
Math.sign(number)
La división del número por su valor absoluto también da su signo. El uso del operador AND lógico de cortocircuito nos permite aplicar un caso especial
0
para que no terminemos dividiendo por él:fuente
var sign = number && number / Math.abs(number);
en el casonumber = 0
0
debe estar en mayúsculas especiales. Respuesta actualizada en consecuencia. Gracias :)La función que está buscando se llama signum y la mejor manera de implementarla es:
fuente
¿No debería esto admitir los ceros firmados de JavaScript (ECMAScript)? Parece funcionar cuando se devuelve x en lugar de 0 en la función "megafast":
Esto lo hace compatible con un borrador de Math.sign ( MDN ) de ECMAScript :
fuente
Para las personas que estén interesadas en lo que está sucediendo con los navegadores más recientes, en la versión ES6 hay un método Math.sign nativo . Puedes consultar el soporte aquí .
Básicamente se vuelve
-1
,1
,0
oNaN
fuente
Superrápido si no necesita Infinity y sabe que el número es un entero, que se encuentra en la fuente openjdk-7:
java.lang.Integer.signum()
fuente
Pensé en agregar esto solo por diversión:
0 y NaN devolverá -1
funciona bien en +/- Infinity
fuente
Una solución que funciona con todos los números, así como con
0
y-0
, así como conInfinity
y-Infinity
, es:Consulte la pregunta " ¿Son iguales +0 y -0? " Para obtener más información.
Advertencia: Ninguna de estas respuestas, incluyendo el ahora estándar
Math.sign
de trabajo voluntad en el caso0
vs-0
. Puede que esto no sea un problema para usted, pero en ciertas implementaciones de física puede ser importante.fuente
Puede cambiar el número y comprobar el bit más significativo (MSB). Si el MSB es un 1, entonces el número es negativo. Si es 0, entonces el número es positivo (o 0).
fuente
var sign = number < 0 : 1 : 0
n & 0x80000000
como una máscara de bits. En cuanto a la conversión a 0,1, -1:n && (n & 0x80000000 ? -1 : 1)
-5e32
y se rompió.ToInt32
. Si lee allí (sección 9.5), hay un módulo que afecta el valor de los números, ya que el rango de un entero de 32 bits es menor que el rango del tipo js Number. Entonces no funcionará para esos valores o los infinitos. Aunque todavía me gusta la respuesta.Estaba a punto de hacer la misma pregunta, pero llegué a una solución antes de terminar de escribir, vi que esta Pregunta ya existía, pero no vi esta solución.
(n >> 31) + (n > 0)
aunque parece ser más rápido al agregar un ternario
(n >> 31) + (n>0?1:0)
fuente
Muy similar a la respuesta de Martijn es
Lo encuentro más legible. Además (o, según su punto de vista, sin embargo), también asimila cosas que pueden interpretarse como un número; por ejemplo, regresa
-1
cuando se le presenta'-5'
.fuente
No veo ningún sentido práctico de devolver -0 y 0 de,
Math.sign
por lo que mi versión es:fuente
Los métodos que conozco son los siguientes:
Math.sign (n)
var s = Math.sign(n)
Esta es la función nativa, pero es la más lenta de todas debido a la sobrecarga de una llamada de función. Sin embargo, maneja 'NaN' donde los otros a continuación pueden simplemente asumir 0 (es decir, Math.sign ('abc') es NaN).
((n> 0) - (n <0))
var s = ((n>0) - (n<0));
En este caso, solo el lado izquierdo o derecho puede ser un 1 según el signo. Esto da como resultado
1-0
(1),0-1
(-1) o0-0
(0).La velocidad de este parece estar a la par con el siguiente a continuación en Chrome.
(n >> 31) | (!! n)
var s = (n>>31)|(!!n);
Utiliza el "desplazamiento a la derecha de propagación de señales". Básicamente, el desplazamiento de 31 elimina todos los bits excepto el signo. Si se estableció el signo, esto da como resultado -1; de lo contrario, es 0. A la derecha,
|
se comprueba si es positivo al convertir el valor a booleano (0 o 1 [BTW: cadenas no numéricas, como!!'abc'
, se convierten en 0 en este caso, y not NaN]) luego usa una operación OR bit a bit para combinar los bits.Este parece el mejor rendimiento promedio en todos los navegadores (mejor en Chrome y Firefox al menos), pero no el más rápido en TODOS. Por alguna razón, el operador ternario es más rápido en IE.
n? n <0? -1: 1: 0
var s = n?n<0?-1:1:0;
Más rápido en IE por alguna razón.
jsPerf
Pruebas realizadas: https://jsperf.com/get-sign-from-value
fuente
Mis dos centavos, con una función que devuelve los mismos resultados que Math.sign haría, es decir, signo (-0) -> -0, signo (-Infinito) -> -Infinito, signo (nulo) -> 0 , signo (indefinido) -> NaN, etc.
Jsperf no me deja crear una prueba o revisión, lo siento por no poder proporcionarle pruebas (le di una oportunidad a jsbench.github.io, pero los resultados parecen mucho más cercanos entre sí que con Jsperf ...)
Si alguien pudiera agregarlo a una revisión de Jsperf, tendría curiosidad por ver cómo se compara con todas las soluciones dadas anteriormente ...
¡Gracias!
Jim.
EDITAR :
Debería haber escrito:
(en
(+x && -1)
lugar de(x && -1)
) para manejarsign('abc')
correctamente (-> NaN)fuente
Math.sign no es compatible con IE 11. Estoy combinando la mejor respuesta con la respuesta de Math.sign:
Ahora, se puede usar Math.sign directamente.
fuente