usar ejemplo codigo java language-design unsigned integer

java - ejemplo - jlabel netbeans



¿Por qué Java no soporta entradas sin firma? (15)

¿Por qué Java no incluye soporte para enteros sin signo?

Me parece una extraña omisión, dado que permiten escribir un código que es menos probable que produzca desbordamientos en una entrada inesperadamente grande.

Además, el uso de enteros sin signo puede ser una forma de autodocumentación, ya que indican que el valor que el int. Sin signo estaba destinado a mantener nunca se supone negativo.

Por último, en algunos casos, los enteros sin signo pueden ser más eficientes para ciertas operaciones, como la división.

¿Cuál es la desventaja de incluir estos?


Con JDK8 tiene algún soporte para ellos.

Aún podemos ver soporte completo de tipos sin firma en Java a pesar de las preocupaciones de Gosling.


Creo que Java está bien como está, agregar sin firmar lo complicaría sin mucho beneficio. Incluso con el modelo de enteros simplificado, la mayoría de los programadores de Java no saben cómo se comportan los tipos numéricos básicos; simplemente lea el libro Puzzlers de Java para ver qué conceptos erróneos puede tener.

En cuanto a consejos prácticos:

  • Si sus valores son de un tamaño algo arbitrario y no encajan en int , use long . Si no encajan en BigInteger uso long .

  • Utilice los tipos más pequeños solo para matrices cuando necesite ahorrar espacio.

  • Si necesita exactamente 64/32/16/8 bits, use long / int / short / byte y deje de preocuparse por el bit de signo, excepto por división, comparación, desplazamiento a la derecha y conversión.

Vea también this respuesta sobre "portar un generador de números aleatorios de C a Java".


Esta es una pregunta más antigua y Pat mencionó brevemente a char, pensé que debería ampliar esto para que otros lo vean en el futuro. Echemos un vistazo más de cerca a los tipos primitivos de Java:

byte - entero de 8 bits con signo

short - entero de 16 bits con signo

int - entero de 32 bits con signo

long - entero de 64 bits con signo

char - char 16 bits (entero sin signo)

Aunque char no admite aritmética unsigned , esencialmente se puede tratar como un entero unsigned signo. Tendría que volver a convertir explícitamente las operaciones aritméticas en char , pero le proporciona una manera de especificar números unsigned .

char a = 0; char b = 6; a += 1; a = (char) (a * b); a = (char) (a + b); a = (char) (a - 16); b = (char) (b % 3); b = (char) (b / a); //a = -1; // Generates complier error, must be cast to char System.out.println(a); // Prints ? System.out.println((int) a); // Prints 65532 System.out.println((short) a); // Prints -4 short c = -4; System.out.println((int) c); // Prints -4, notice the difference with char a *= 2; a -= 6; a /= 3; a %= 7; a++; a--;

Sí, no hay soporte directo para enteros sin signo (obviamente, no tendría que volver a convertir la mayoría de mis operaciones en char si hubiera soporte directo). Sin embargo, ciertamente existe un tipo de datos primitivo sin firmar. También me gustaría haber visto un byte sin firmar, pero supongo que duplicar el costo de la memoria y, en cambio, usar char es una opción viable.

Editar

Con JDK8 hay nuevas API para Long y Integer que proporcionan métodos de ayuda cuando se tratan valores long e int como valores sin signo.

  • compareUnsigned
  • divideUnsigned
  • parseUnsignedInt
  • parseUnsignedLong
  • remainderUnsigned
  • toUnsignedLong
  • toUnsignedString

Además, Guava proporciona varios métodos de ayuda para hacer cosas similares para los tipos de enteros que ayudan a cerrar la brecha que deja la falta de soporte nativo para enteros unsigned .


Esto es de una entrevista con Gosling y otros , sobre la simplicidad:

Gosling: Para mí, como diseñador de idiomas, lo que realmente no me considero como en estos días, lo que realmente significa "realmente" terminó siendo lo que podía esperar de que J. Random Developer tuviera la especificación en su cabeza. Esa definición dice que, por ejemplo, Java no lo es, y de hecho, muchos de estos lenguajes terminan con muchos casos, cosas que nadie entiende realmente. Pregúntele a cualquier desarrollador de C acerca de no firmado, y pronto descubrirá que casi ningún desarrollador de C realmente entiende lo que sucede con unsigned, qué es la aritmética sin firmar. Cosas como esas hicieron que C complejo. La parte del lenguaje de Java es, creo, bastante simple. Las bibliotecas que hay que buscar.


He escuchado historias que iban a incluirse cerca del lanzamiento original de Java. Oak fue el precursor de Java, y en algunos documentos de especificaciones se mencionaron los valores de uso. Desafortunadamente, estos nunca llegaron al lenguaje Java. En la medida en que alguien ha podido descubrir que simplemente no se implementó, probablemente debido a una restricción de tiempo.


Java tiene tipos sin firmar, o al menos uno: char es un corto sin firmar. Entonces, cualquiera que sea la excusa que Gosling arroje, es realmente su ignorancia, por qué no hay otros tipos sin firma.

También los tipos cortos: los cortos se usan todo el tiempo para multimedia. El motivo es que puede ajustar 2 muestras en un solo largo de 32 bits sin firmar y vectorizar muchas operaciones. Lo mismo con los datos de 8 bits y el byte sin firmar. Puede colocar 4 u 8 muestras en un registro para vectorizar.


La razón por la cual IMHO es porque son / eran demasiado perezosos para implementar / corregir ese error. Sugerir que los programadores de C / C ++ no entienden sin signo, estructura, unión, marca de bit ... Es simplemente absurdo.

Si estuvieras hablando con un programador básico / bash / java a punto de comenzar a programar a la C, sin un conocimiento real de este lenguaje, o simplemente estás hablando de tu mente. ;)

cuando tratas todos los días en formato de archivo o hardware, comienzas a cuestionar qué demonios estaban pensando.

Un buen ejemplo aquí sería tratar de usar un byte sin signo como un bucle auto giratorio. Para aquellos de ustedes que no comprenden la última oración, cómo se llaman programadores.

corriente continua


Leyendo entre líneas, creo que la lógica era algo así:

  • En general, los diseñadores de Java querían simplificar el repertorio de tipos de datos disponibles.
  • para fines cotidianos, sentían que la necesidad más común era para los tipos de datos firmados
  • para implementar ciertos algoritmos, a veces se necesita aritmética no firmada, pero el tipo de programadores que implementaría tales algoritmos también tendrían el conocimiento para "trabajar" haciendo aritmética no firmada con tipos de datos firmados

Sobre todo, diría que fue una decisión razonable. Posiblemente, tendría:

  • byte sin signo, o al menos han proporcionado una alternativa firmada / unsigned, posiblemente con nombres diferentes, para este tipo de datos (hacer que se firme es bueno para la coherencia, pero ¿cuándo necesita un byte firmado?)
  • eliminado "corto" (¿cuándo fue la última vez que usaste aritmética con signo de 16 bits?)

Aún así, con un poco de kludging, las operaciones en valores sin firmar de hasta 32 bits no son tan malas, y la mayoría de las personas no necesitan una división o comparación de 64 bits sin firmar.


Porque el tipo unsigned es puro mal.

El hecho de que en C unsigned - int produce unsigned es aún más perverso.

Aquí hay una instantánea del problema que me quemó más de una vez:

// We have odd positive number of rays, // consecutive ones at angle delta from each other. assert( rays.size() > 0 && rays.size() % 2 == 1 ); // Get a set of ray at delta angle between them. for( size_t n = 0; n < rays.size(); ++n ) { // Compute the angle between nth ray and the middle one. // The index of the middle one is (rays.size() - 1) / 2, // the rays are evenly spaced at angle delta, therefore // the magnitude of the angle between nth ray and the // middle one is: double angle = delta * fabs( n - (rays.size() - 1) / 2 ); // Do something else ... }

¿Has notado el error ya? Confieso que solo lo vi después de intervenir con el depurador.

Debido a que n es del tipo sin signo size_t la expresión completa n - (rays.size() - 1) / 2 evalúa como unsigned . Se pretende que esa expresión sea una posición con signo del rayo n desde el medio: el primer rayo desde el medio en el lado izquierdo tendría la posición -1, el primero en la derecha tendría la posición +1, etc. Después de tomar el valor de abs y multiplicarlo por el ángulo delta obtendría el ángulo entre el rayo n th y el del medio.

Desafortunadamente para mí, la expresión anterior contenía el mal sin signo y en lugar de evaluar a, digamos, -1, evaluó a 2 ^ 32-1. La posterior conversión a double sellado del error.

Después de que un error o dos causados ​​por el mal uso de la aritmética unsigned uno tiene que comenzar a preguntarse si el bit extra que recibe recibe el problema. Intento, en la medida de lo posible, evitar cualquier uso de tipos unsigned en aritmética, aunque todavía lo uso para operaciones no aritméticas como las máscaras binarias.


Puedo pensar en un desafortunado efecto secundario. En las bases de datos integradas de Java, el número de ID que puede tener con un campo de ID de 32 bits es 2 ^ 31, no 2 ^ 32 (~ 2billion, no ~ 4billion).


Sé que este post es demasiado viejo; sin embargo, para su interés, en Java 8 y versiones posteriores, puede usar el tipo de datos int para representar un entero de 32 bits sin signo, que tiene un valor mínimo de 0 y un valor máximo de 2 32 −1. Use la clase Integer para usar el tipo de datos int como un entero sin signo y se compareUnsigned() métodos estáticos como compareUnsigned() , divideUnsigned() etc. a la clase Integer para admitir las operaciones aritméticas para enteros sin signo.


Su pregunta es "¿Por qué Java no admite entradas sin firma"?

Y mi respuesta a su pregunta es que Java quiere que todos sus tipos primitivos: byte , char , short , int y long se traten como byte , word , dword y qword respectivamente, exactamente como en ensamblador, y los operadores de Java están firmados las operaciones en todos sus tipos primitivos, excepto para char , pero solo en char , tienen solo 16 bits sin firmar.

Por lo tanto, los métodos estáticos suponen ser operaciones sin firma también para 32 y 64 bits.

Necesita una clase final, cuyos métodos estáticos se pueden llamar para las operaciones sin firmar .

Puede crear esta clase final, llamarlo como se llame e implementar sus métodos estáticos.

Si no tiene idea de cómo implementar los métodos estáticos, este link puede ayudarlo.

En mi opinión, Java no se parece en nada a C ++, si no admite tipos sin firma ni sobrecarga de operadores, por lo que creo que Java debe tratarse como un lenguaje completamente diferente de C ++ y de C.

También es completamente diferente en el nombre de los idiomas por cierto.

Por lo tanto, no recomiendo en Java escribir código similar a C y no recomiendo escribir código similar a C ++, porque en Java no podrás hacer lo que quieras hacer a continuación en C ++, es decir, el código no seguirá siendo C ++ como en absoluto y para mí es malo codificar así, para cambiar el estilo en el medio.

Recomiendo escribir y usar métodos estáticos también para las operaciones firmadas, por lo que no se ve en la mezcla de códigos de operadores y métodos estáticos para las operaciones firmadas y no firmadas, a menos que solo necesite operaciones firmadas en el código, y está bien Utilice solo los operadores.

También recomiendo evitar el uso de tipos primitivos cortos , int y largos , y usar word , dword y qword respectivamente, y se trata de llamar a los métodos estáticos para operaciones sin firma y / o operaciones firmadas en lugar de utilizar operadores.

Si está a punto de realizar operaciones firmadas solamente y usa los operadores solo en el código, entonces está bien usar estos tipos primitivos short , int y long .

En realidad, word , dword y qword no existen en el lenguaje, pero puede crear una nueva clase para cada uno y la implementación de cada uno debería ser muy fácil:

La palabra de clase mantiene el tipo primitivo solo corto , la clase dword contiene el tipo primitivo int solamente y la clase qword mantiene el tipo primitivo solo por mucho tiempo . Ahora todos los métodos sin firmar y firmados como estáticos o no como su elección, puede implementar en cada clase, es decir, todas las operaciones de 16 bits sin firmar y firmadas al dar nombres de significado en la clase de palabras , todas las operaciones de 32 bits sin firmar y firmado al dar nombres de significado en la clase dword y todas las operaciones de 64 bits sin firmar y firmadas al dar nombres de significado en la clase qword .

Si no le gusta dar demasiados nombres diferentes para cada método, siempre puede usar la sobrecarga en Java, es bueno leer que Java no lo eliminó también.

Si desea métodos en lugar de operadores para operaciones con signo de 8 bits y métodos para operaciones sin signo de 8 bits que no tienen ningún operador, puede crear la clase de bytes (tenga en cuenta que la primera letra ''B'' es mayúscula, por lo que no byte de tipo primitivo) e implementar los métodos en esta clase.

Acerca de pasar por valor y pasar por referencia:

Si no estoy equivocado, como en C #, los objetos primitivos se pasan naturalmente por valor, pero los objetos de clase se pasan naturalmente por referencia, lo que significa que los objetos de tipo Byte , word , dword y qword se pasarán por referencia y no por valor por defecto. Desearía que Java tuviera objetos struct como C #, así que todo el byte , word , dword y qword podrían implementarse como struct en lugar de clase , por lo que, de forma predeterminada, se pasaron por valor y no por referencia de forma predeterminada, como cualquier objeto struct en C # , al igual que los tipos primitivos, se pasan por valor y no por referencia por defecto, pero debido a que Java es peor que C # y tenemos que lidiar con eso, entonces solo hay clases e interfaces, que se pasan por referencia y no por valor por defecto. Por lo tanto, si desea pasar los objetos Byte , word , dword y qword por valor y no por referencia, como cualquier otro objeto de clase en Java y también en C #, tendrá que usar simplemente el constructor de copia y eso es todo.

Esa es la única solución en la que puedo pensar. Solo desearía poder teclear los tipos primitivos a word, dword y qword, pero Java no admite typedef ni usa en absoluto, a diferencia de C # que admite el uso , que es equivalente a typedef de C.

Acerca de la salida:

Para la misma secuencia de bits , puede imprimirlos de muchas maneras: como binario, como decimal (como el significado de% u en C printf), como octal (como el significado de% o en C printf), como hexadecimal (como el significado de% x en C printf) y como entero (como el significado de% d en C printf).

Tenga en cuenta que C printf no conoce el tipo de las variables que se pasan como parámetros a la función, por lo que printf conoce el tipo de cada variable solo desde el objeto char * pasado al primer parámetro de la función.

Entonces, en cada una de las clases: Byte , word , dword y qword , puede implementar el método de impresión y obtener la funcionalidad de printf, a pesar de que el tipo primitivo de la clase está firmado, aún puede imprimirlo sin firmar siguiendo un algoritmo que incluya Operaciones lógicas y de desplazamiento para obtener los dígitos para imprimir en la salida.

Desafortunadamente, el enlace que le proporcioné no muestra cómo implementar estos métodos de impresión, pero estoy seguro de que puede buscar los algoritmos que necesita para implementar estos métodos de impresión.

Eso es todo lo que puedo responder a tu pregunta y sugerirte.


Tan pronto como las palabras firmadas y no firmadas se mezclan en una expresión, las cosas comienzan a ensuciarse y probablemente perderá información. La restricción de Java a las entradas firmadas realmente solo aclara las cosas. Me alegra no tener que preocuparme por todo el negocio firmado / sin firmar, aunque a veces pierdo el octavo bit en un byte.


Una vez tomé un curso de C ++ con alguien en el comité de estándares de C ++ que dio a entender que Java tomó la decisión correcta para evitar tener enteros sin signo porque (1) la mayoría de los programas que usan enteros sin signo pueden hacerlo igual que los enteros con signo y esto es más natural términos de cómo piensa la gente, y (2) el uso de enteros sin signo resulta en muchos problemas fáciles de crear pero difíciles de depurar, como el desbordamiento aritmético de enteros y la pérdida de bits significativos al convertir entre tipos con signo y sin signo. Si resta por error 1 de 0 utilizando enteros con signo, a menudo hace que su programa se bloquee y facilita la búsqueda del error que si se ajusta a 2 ^ 32 - 1, y los compiladores y las herramientas de análisis estático y las verificaciones de tiempo de ejecución tienen que asume que sabes lo que estás haciendo ya que elegiste usar aritmética sin firma. Además, los números negativos como -1 a menudo pueden representar algo útil, como un campo que se ignora / omite / desactiva, mientras que si estuviera usando sin firmar, tendría que reservar un valor especial como 2 ^ 32 - 1 o algo similar.

Hace mucho tiempo, cuando la memoria estaba limitada y los procesadores no funcionaban automáticamente en 64 bits a la vez, cada bit contaba mucho más, por lo que tener bytes o cortos firmados o sin firmar realmente importaba mucho más a menudo y obviamente era la decisión de diseño correcta. Hoy en día, solo el uso de un int firmado es más que suficiente en casi todos los casos de programación regular, y si su programa realmente necesita usar valores mayores que 2 ^ 31 - 1, a menudo solo desea un largo tiempo. Una vez que estás en el territorio de usar largos, es aún más difícil encontrar una razón por la que realmente no puedas arreglártelas con 2 ^ 63 - 1 enteros positivos. Siempre que vayamos a procesadores de 128 bits será un problema aún menor.