values template not last item handlebars example javascript algorithm numbers sign

javascript - not - handlebars template js



Number.sign() en javascript (14)

¿No debería esto admitir los ceros firmados de JavaScript (ECMAScript)? Parece que funciona al devolver x en lugar de 0 en la función "megafast":

function sign(x) { return typeof x === ''number'' ? x ? x < 0 ? -1 : 1 : x === x ? x : NaN : NaN; }

Esto lo hace compatible con un borrador de Math.sign ( MDN ) de ECMAScript :

Devuelve el signo de la x, que indica si x es positivo, negativo o cero.

  • Si x es NaN, el resultado es NaN.
  • Si x es -0, el resultado es -0.
  • Si x es +0, el resultado es +0.
  • Si x es negativo y no -0, el resultado es -1.
  • Si x es positivo y no +0, el resultado es +1.

¿Te preguntas si hay formas no triviales de encontrar el signo del número ( función signum )?
Pueden ser soluciones más cortas / más rápidas / más elegantes que la obvia

var sign = number > 0 ? 1 : number < 0 ? -1 : 0;

Breve extracto

Usa esto y estarás seguro y rápido

function sign(x) { return typeof x === ''number'' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN; }

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 cast menor, más performant, 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 es un número legal en JS, esta solución no parece totalmente correcta.

3. El arte ... pero muy lento [más lento]

function sign(x) { return (x > 0) - (x < 0); }

4. Usando el cambio de bit
rápido, pero sign(-Infinity) -> 0

function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }

5. Tipo seguro [megafast]

! Parece que los navegadores (especialmente el v8 de Chrome) hacen algunas optimizaciones mágicas y esta solución resulta mucho más eficiente que otras, incluso (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

  • pruebas de jsperf ;
  • fiddle - pruebas de tipo de lanzamiento;

¡Las mejoras son bienvenidas!

[Offtopic] Respuesta aceptada

  • Andrey Tarantsov - +100 para 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 genial, pero definitivamente no es cómo deberían hacerse las cosas, ¿eh? 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 si tomo todo en conjunto, considero que este enfoque es el mejor. Vote por él :)


Dividir el número por su valor absoluto también le da su signo. El uso del operador AND lógico de cortocircuito nos permite un caso especial 0 por lo que no terminaremos dividiéndolo:

var sign = number && number / Math.abs(number);


Estaba a punto de hacer la misma pregunta, pero llegué a una solución antes de que terminara de escribir, vi que esta Cuestión ya existía, pero no vi esta solución.

(n >> 31) + (n > 0)

parece ser más rápido al agregar un ternario (n >> 31) + (n>0?1:0)


La función que está buscando se llama signum , y la mejor manera de implementarla es:

function sgn(x) { return (x > 0) - (x < 0); }


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 a función. Sin embargo, maneja ''NaN'' donde los otros de abajo pueden 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 basado en el signo. Esto resulta en 1-0 (1), 0-1 (-1) o 0-0 (0).

La velocidad de este parece estar en la misma línea que la siguiente en Chrome.

(n >> 31) | (!! n)

var s = (n>>31)|(!!n);

Utiliza el "cambio a la derecha que propaga la señal". Básicamente cambiando en 31 gotas todos los bits excepto el signo. Si se estableció el signo, esto da como resultado -1, de lo contrario, es 0. Derecho de | prueba positivo al convertir el valor en booleano (0 o 1 [BTW: cadenas no numéricas, como !!''abc'' , ser 0 en este caso, y no NaN]) luego usa una operación O bit a bit para combinar los bits .

Este parece ser 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


Mis dos centavos, con una función que arroja los mismos resultados que Math.sign, es decir, firmar (-0) -> -0, firmar (-Infinito) -> -Infinito, firmar (nulo) -> 0 , signo (indefinido) -> NaN, etc.

function sign(x) { return +(x > -x) || (x && -1) || +x; }

Jsperf no me permitirá crear una prueba o revisión, lo siento por no poder proporcionarle las 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 por favor agregarlo a una revisión de Jsperf, me gustaría saber cómo se compara con todas las soluciones anteriores ...

¡Gracias!

Jim.

EDITAR :

Debería haber escrito:

function sign(x) { return +(x > -x) || (+x && -1) || +x; }

( (+x && -1) lugar de (x && -1) ) para manejar el sign(''abc'') correctamente (-> NaN)


Muy similar a la respuesta de Martijn es

function sgn(x) { isNaN(x) ? NaN : (x === 0 ? x : (x < 0 ? -1 : 1)); }

Lo encuentro más legible También (o, dependiendo de su punto de vista, sin embargo), también asimila cosas que pueden interpretarse como un número; por ejemplo, devuelve -1 cuando se presenta con ''-5'' .


No veo ningún sentido práctico de devolver -0 y 0 de Math.sign así que mi versión es:

function sign(x) { x = Number(x); if (isNaN(x)) { return NaN; } if (x === -Infinity || 1 / x < 0) { return -1; } return 1; }; sign(100); // 1 sign(-100); // -1 sign(0); // 1 sign(-0); // -1


Para las personas que están interesadas en lo que está sucediendo con los últimos navegadores, en la versión ES6 hay un método MDN nativo. Puede consultar el soporte aquí .

Básicamente devuelve -1 , 1 , 0 o NaN

Math.sign(3); // 1 Math.sign(-3); // -1 Math.sign(''-3''); // -1 Math.sign(0); // 0 Math.sign(-0); // -0 Math.sign(NaN); // NaN Math.sign(''foo''); // NaN Math.sign(); // NaN


Pensé en agregar esto solo por diversión:

function sgn(x){ return 2*(x>0)-1; }

0 y NaN devolverán -1
funciona bien en +/- Infinity


Podría cambiar el número y verificar 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).


Una solución que funciona en todos los números, así como 0 y -0 , así como Infinity e -Infinity , es:

function sign( number ) { return 1 / number > 0 ? 1 : -1; }

Consulte la pregunta " ¿Son +0 y -0 lo mismo? " Para obtener más información.

Advertencia: ninguna de estas respuestas, incluido el MDN ahora estándar funcionará en el caso 0 vs -0 . Esto puede no ser un problema para ti, pero en ciertas implementaciones de física puede ser importante.


Versión más elegante de solución rápida:

var sign = number?number<0?-1:1:0


var sign = number >> 31 | -number >>> 31;

Superrápido si no necesita Infinito y sepa que el número es un número entero, que se encuentra en la fuente openjdk-7: java.lang.Integer.signum()