Comprendre la différence entre int et Integer et BigInteger en java et float et double

L'autre jour, quand j'ai posé la question précédente du concours de programmation avec haskell, quand j'ai écrit la logique pour gérer l'alimentation, je voulais que le résultat final soit «12340000», mais il n'a pas passé parce que c'était «12340000.0». C'est gênant.

C'est embarrassant, mais écouter est aussi un commentaire sur la honte d'une vie, et ce que vous ne savez pas peut être fait si vous apprenez et maîtrisez docilement. Tu ne peux pas?

Je ne suis pas sûr, mais en bref, c'est une histoire sur la mise en place de choses comme «int» que j'ai utilisé d'une manière vague.

Fond clair

Je crée généralement un système de gestion de contrat avec java / DDD, mais les nombres que je gère ne sont que des dizaines de milliers d'entiers. C'est un peu yen, en comptant le nombre de contrats, et ainsi de suite. Il n'y a pas de facturation quotidienne pour le mois. Je suis surpris.

Grâce à l'objet de valeur de DDD, je ne touche pas souvent à ʻint` brut.

Donc, juste avant d'écrire cet article, par exemple, le degré de compréhension de Java est comme ça.

" Byte? Je ne sais pas, mais j'ai peur. " "" Long "? " BigInteger? Dekaso ~ " "Flotteur"? Fluffy ~ " " Double? Qu'est-ce que double ~?

Le degré de compréhension. C'est sérieux.

(Je savais seulement que le double italien était doppio)

Alors, reconnaissez simplement que beaucoup de gens l'ont mis ensemble!

Merci pour la version haskell

J'utilise java comme langue de confirmation pour cet article.

À l'origine, je l'ai vérifié avec haskell, mais j'ai pensé qu'il serait préférable de vérifier certaines langues, alors je l'ai également essayé avec java.

Je l'ai vérifié un peu avec python, mais je pense que je vais utiliser haskell, qui est ma vraie vie, et java, que j'utilise au travail.

Alors, merci pour votre coopération. → Comprendre la différence entre Haskell's Int et Integer, Float, Double et Rational

Premier aperçu

Avant d'entrer dans la programmation, parlons des mathématiques.

Même si vous parlez de mathématiques, des choses effrayantes comme l'algèbre et la théorie des sphères ne sortent pas. J'ai peur aussi. Il s'agit du lycée.

Regardez ceci en premier.

スクリーンショット 2020-03-15 23.42.35.png

Je vais l'expliquer grossièrement.

Réel et imaginaire

Les nombres que vous voyez habituellement sont généralement des «nombres réels».

D'un autre côté, les «nombres imaginaires» sont inventés parce qu'ils sont pratiques, mais ils n'existent pas réellement. Un exemple typique est «√-1» ou il est exprimé par «i». C'est facile à comprendre. Je ne suis pas sûr.

Le «nombre imaginaire» est ** un nombre qui correspond à un nombre réel inférieur à 0 **, et le «nombre réel» est défini comme ** sinon **.

Je ne veux pas y réfléchir en détail, il est donc normal d'utiliser "about` nombre réel" ".

Chiffres rationnels et déraisonnables

La classification des «nombres réels» est prise au sérieux.

Les «nombres réels» sont grossièrement divisés en «nombres rationnels» et «nombres raisonnables», mais les «nombres rationnels» sont des ** nombres qui peuvent être représentés par des rapports d'entiers **.

D'autre part, d'autres nombres ** qui ne peuvent pas être exprimés par le rapport d'entiers sont appelés «nombres non raisonnables».

Entiers, fractions finies et fractions circulaires

Les deux sont des «nombres raisonnables».

Il n'est pas nécessaire d'expliquer «entier». «3» peut être exprimé par «3/1», c'est donc un «nombre raisonnable».

Une fraction finie est une "fraction" avec une fin, telle que "0,5". Il peut être exprimé sous la forme d'un rapport «entier» comme «1/2».

D'autre part, les "fractions" telles que "0,333 ..." et "0,142857142857142857 ..." dans lesquelles le même nombre est répété indéfiniment sont appelées "fractions circulaires". Cela peut également être exprimé sous la forme d'un rapport de "nombres entiers" tels que "1/3" et "1/7".

Entiers négatifs, entiers positifs, zéros et nombres naturels

ʻInteger` est le plus connu, donc je ne pense pas que ce soit un problème, mais pour le moment.

L '«entier négatif» est «-1» ou «-5», qui peut être exprimé sous la forme de «-5 / 1».

«0» est «0/1», n'est-ce pas?

La même chose est vraie pour les «entiers positifs».

De plus, un «entier positif» est appelé un «nombre naturel». (Peu importe si vous incluez «0» dans cet article)

Fractions et minutes

Un supplément à «minorité» et «fraction».

Une «fraction» est un nombre exprimé par ** un rapport de nombres **, et à première vue, il semble être identique à un «nombre rationnel». Cependant, comme les «nombres rationnels» sont des ** ratios d'entiers **, les fractions sont un concept plus large.

Par exemple, il y a «1 / √2». Il s'agit d'un "nombre raisonnable" car ce n'est pas un ** rapport d'entiers **. (Comme il est d'environ 0,7, lorsqu'il est au carré, il est d'environ «0,5», ce qui est plus grand que «0», donc ce n'est pas un «nombre imaginaire».)

De plus, par exemple, il existe un "nombre infini", mais dans la figure précédente, le "nombre circulaire" et le "nombre irrationnel" du "nombre rationnel" sont tous deux des "nombres infinis". C'est la différence entre circulant et non circulant.

L'anglais que vous voulez garder

Tout en gardant à l'esprit les points ci-dessus, nous, les programmeurs, devons connaître les mots anglais, nous allons donc les résumer grossièrement. (Bien que l'anglais soit également inclus dans l'image.)

Le «nombre réel» est le «nombre réel» et le «nombre imaginaire» est le «nombre imaginaire», il est donc facile d'obtenir une image.

Pas très familier, mais le «nombre rationnel» est le «nombre rationnel». Si vous l'écrivez en copie, vous le frapperez rarement.

Puisque «ratio» signifie «ratio», certaines personnes peuvent l'avoir utilisé dans le nom de la variable.

De plus, bien que non montré dans l'image, «décimal» est «décimal» et «fraction» est «fraction».

Vers le monde de la programmation (java)

J'aimerais voir l'exemple de code en java à la fois, mais il y a de grandes différences entre le monde humain et le monde informatique.

Autrement dit, «la mémoire est finie».

Là où il se rapporte, par exemple, "grand nombre" et "fraction infinie".

Entier de longueur fixe

Par exemple, ʻint de java est un ʻentier fixe de 32 bits.

En raison de la mémoire limitée d'un ordinateur, nous limitons nos nombres à la plage de 32 «0 | 1».

Entier multiple

D'autre part, "multi-fold integer" est une méthode d'expression de nombres ** qui alloue dynamiquement de la mémoire en fonction du nombre à traiter.

En théorie, vous pouvez gérer un nombre infini. (Bien sûr, tant que la mémoire de l'ordinateur le permet.)

Entiers de longueur fixe et entiers de longueur multiple

Cet entier de longueur fixe provoque le débordement que tout le monde aime.

Par exemple, java'byte` est un "entier" fixe de 8 bits. Le premier bit est utilisé comme signe positif / négatif et le reste est utilisé pour représenter la valeur.

0000|0000De1Commençant à augmenter petit à petit0111|1111De1000|0000Débordement où 1111|1111De1|0000|0000Le 9ème bit est hors de portée au point où0000|0000Sera traité comme. (| Est inséré tous les 4 chiffres pour une visualisation facile.)

スクリーンショット 2020-03-16 0.36.23.png

D'autre part, «BigInteger» est «un entier de plusieurs longueurs». Lorsqu'un débordement de chiffres est sur le point de se produire, il alloue dynamiquement de la mémoire afin qu'il ne déborde pas.

スクリーンショット 2020-03-16 2.43.29.png

(La figure ci-dessus est une image car elle dépend de la méthode de montage pour contenir le code et la valeur.)

L '«entier de longueur fixe» est excellent en termes d'efficacité et de performance de la mémoire, et l' «entier de longueur multiple» est d'une excellente précision. Ce sont les bonnes personnes au bon endroit.

Point flottant

Il existe une idée similaire pour les «fractions» ainsi que pour les «entiers».

«Virgule flottante» est l'une des ** méthodes de représentation des nombres **, et est une méthode de représentation qui a une «partie formelle» et une «partie exposante» de «longueur fixe».

En gros, on peut penser que la «partie implicite» représente une valeur et la «partie exponentielle» représente un chiffre.

Par exemple, le nombre binaire «0,00000101» est exprimé par «101 * 2 ^ -8».

Cependant, dans ce cas, il peut être exprimé par «10.1 * 2 ^ -7», il est donc décidé que la «partie incorrecte» devrait être «1.x» dans la norme appelée «IEEE754». Donc c'est "1.01 * 2 ^ -6". J'écris aussi «1.01e-6».

C'est celui avec «e» qui apparaît parfois lors de l'écriture de code. J'avais peur mais je l'ai surmonté.

Je me demande si cela s'appelle «virgule flottante» parce que la position pour atteindre la virgule décimale change en fonction de la «partie formelle» et de la «partie exponentielle». D'autre part, le mot apparié est «décimal fixe», qui comprend, par exemple, «entier».

Vérifier avec java

L'introduction est devenue plus longue. De là, nous vérifierons avec Gashigashi java.

type description
octet, octet 8 bits entier de longueur fixe
court, court entier de longueur fixe 16 bits
int, Integer Entier de longueur fixe 32 bits
long, Long Entier de longueur fixe de 64 bits
float, Float Virgule flottante simple précision (32 bits)
double, Double Virgule flottante double précision (64 bits)
BigInteger Entier multiple
BigDecimal

Le code ci-dessous omet l'équivalent System.out.println et le commentaire sur cette ligne est le résultat.

byte, short, int, long Il y en a beaucoup, mais n'ayez pas peur.

Ce sont tous des «entiers de longueur fixe» et la seule différence est la précision qu'ils peuvent exprimer.

Byte.MAX_VALUE;       // 127
Short.MAX_VALUE;      // 32767
Integer.MAX_VALUE;    // 2147483647
Long.MAX_VALUE;       // 9223372036854775807

Par exemple, si vous entrez + 1 à la limite supérieure de ʻInteger`, il débordera.

Integer.MAX_VALUE + 1;    // -2147483648

Conversion mutuelle

Et bien sûr, passer de moins précis à plus précis est bien, mais pas l'inverse.

short s = 20000;

(int) s;    // 20000
int i = 40000;

(short) i;    // -25536

Au fait, la différence entre int et Integer

C'est différent de l'objectif initial, mais c'est étonnamment intéressant, alors j'aimerais le dire.

En java, ʻint est un type primitif et ʻInteger est un type de classe.

Les principales différences sont, en gros, "ʻint n'autorise pas null" et "ʻint ne peut pas être T tel queList <T>". Il n'y a aucune différence entre ʻint et ʻInteger en termes d'exactitude. C'est important.

De plus, java a un mécanisme qui permet au compilateur de se convertir correctement, donc dans la plupart des cas, vous n'avez pas à vous en soucier trop.

Parler de mémoire avant la conversion mutuelle

Vous n'y pensez peut-être pas trop, mais je vais vous expliquer la zone de pile et la zone de tas très grossièrement.

Par exemple, si vous écrivez un code comme celui-ci. (Pour faciliter la distinction entre les variables ʻint et ʻInteger, ** cet article utilise des lettres majuscules au début du nom de la variable.)

Integer Ia = new Integer(1);

Dans ce cas, la mémoire ressemble à ceci.

スクリーンショット 2020-03-16 1.31.34.png

Si vous faites new, quelque chose sera mis dans la variable ʻIa` dans la zone de pile. D'une manière ou d'une autre, j'ai l'impression que «Ia» contient l'instance elle-même, mais que seule la ** flèche ** la contient. D'une manière effrayante, c'est un ** pointeur **.

L'instance créée se trouve dans la zone du tas.

D'un autre côté, le type primitif ʻint` est réservé tel quel dans la zone de pile.

Integer Ia = new Integer(1);
Integer Ib = new Integer(1);
int ia = 1;
int ib = 1;

Donc, si vous écrivez ce code, l'image ressemblera à celle ci-dessous.

スクリーンショット 2020-03-16 1.36.04.png

Identité et équivalence

Je suis sûr qu'il y a beaucoup de gens qui ont été en colère contre les gens effrayants qui disent: "N'utilisez pas == pour une comparaison en java ", mais voyons pourquoi.

L'identité dans un type de classe consiste à comparer ** la même instance ** et l '«équivalence» est ** la même valeur **. Le premier est fait par == et le second par ʻequals`. L'équivalence dépend également de la mise en œuvre. (Par exemple, dans la comparaison d'entités DDD, seule la correspondance d'identité peut être considérée comme la même valeur.)

Le type primitif == compare simplement les valeurs.

スクリーンショット 2020-03-16 1.40.54.png

Donc ʻIa == Ibest ** faux ** car c'est une flèche avec une destination différente. ʻIa.equals (Ib)est ** true ** car les valeurs de destination sont les mêmes.

Par exemple, "M. A et M. B ont tous deux des boules de 500 yens, ** des pièces physiquement différentes **, mais ** la même valeur **".

boxe automatique et déballage automatique

Maintenant que vous comprenez la zone de pile, la zone de tas et la comparaison, il s'agit de la conversion mutuelle.

ʻInt-> ʻInteger est appelé ** boxing ** et vice versa ** unboxing **. Je pense que c'est une image à mettre dans une boîte de classe wrapper.

Le code suivant peut être exécuté par ** auto boxing | auto unboxing **.

Integer Ia = new Integer(1);
int ia = Ia;                   // unboxing

スクリーンショット 2020-03-16 1.47.07.png

int ib = 1;
Integer Ib = ib;               // boxing

スクリーンショット 2020-03-16 1.47.15.png

En interne, les valeurs sont apportées à la zone de pile et des instances sont créées dans la zone de tas pour obtenir des références. (En fait, la valeur d'origine ne disparaît pas, mais elle est mince car c'est facile à imaginer.)

A part: pièges

Maintenant, lequel des codes suivants serait «vrai» ou «faux»?

int ia = 1;
int ib = 1;
Integer Ia = ia;
Integer Ib = ib;

Ia == Ib;    // true or false ?

Les flèches pour «Ia» et «Ib» devraient être différentes car elles sont «nouvelles» par ** auto boxing **. C'est également le cas sur l'image ci-dessus.

Mais c'est "vrai".

Apparemment, le ** auto boxing ** est réalisé par ʻInteger # valueOf, et le ** auto unboxing ** est réalisé par ʻInteger # intValue.

Integer Ia = Integer.valueOf(ia);
Integer Ib = Integer.valueOf(ib);

Donc, l'essentiel ʻInteger # valueOf`, mais il est implémenté comme ça.

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

Apparemment, le "-128" ~ "127" fréquemment utilisé semble être mis en cache. Donc, dans l'exemple de code ci-dessus, ce n'est pas «nouveau».

Avec un tel code, ce sera «faux» correctement, il semble que la compréhension était correcte et que c'est sûr.

int ia = 1000;
int ib = 1000;
Integer Ia = ia;
Integer Ib = ib;

Ia == Ib;    // false

Au fait, en interne, utiliser ʻInteger # intValue pour ** unboxing automatique ** signifie que si ʻIa est null, ** unboxing automatique ** entraînera une NullPointerException.

Résumé des différences entre int et Integer

C'est vrai.

Dans cet article, ʻint et ʻInteger et float et Float n'ont aucune différence de précision, nous utiliserons donc celui qui vous convient dans l'exemple de code sans préavis.

float, double Vous avez maintenu le «entier». Vient ensuite le «fractionnaire».

Je me demandais ce qu'est le «double», mais c'est clair si vous étudiez. Le float utilisait 32 bits et le double utilisait 64 bits pour représenter la valeur. Donc double précision.

Puisqu'il est impossible de représenter complètement une «fraction infinie» tant que la mémoire de l'ordinateur est finie, elle doit être traitée en supposant qu'une erreur se produira.

Par exemple, le nombre décimal «0,01» ne peut pas être exprimé sous forme de nombre fini s'il s'agit d'un nombre binaire. Comme il ne peut pas être exprimé sous forme de nombre fini, vous devez abandonner quelque part, et si vous le répétez, vous pouvez comprendre que l'erreur augmentera.

Alors, quel genre d'erreur se produira? Essayons.

float f = 0;
for (int i = 0; i < 100; i++) {
    f += 0.01f;
}

double d = 0;
for (int i = 0; i < 100; i++) {
    d += 0.01d;
}

f;    // 0.99999934
d;    // 1.0000000000000007

«double» est plus proche de «1.0».

Conversion mutuelle

La conversion entre «float» et «double», comme «short» et «int », s'arrête lorsqu'elle est convertie de la précision supérieure à la précision inférieure.

f;             // 0.99999934
d;             // 1.0000000000000007

(double) f;    // 0.9999993443489075
(float) d;     // 1.0

Si vous passez de «double» à «float», il manque.

De plus, comme il est fini en premier lieu, une erreur se produira simplement avec les valeurs suivantes.

10d / 3d;       // 3.3333333333333335
1.00000001f;    // 1.0

BigInteger, BigDecimal Merci d'avoir attendu, les gars «multi-longueurs».

Ils allouent la mémoire de manière dynamique en fonction des chiffres, donc il n'y a pas de débordement et pas d'erreur. En quelque sorte incroyable.

Essayons-le tout de suite.

BigDecimal Essayez à partir de la «grande décimale» de la «fraction». Traitons généreusement un énorme «entier» dès le début.

BigDecimal bd = new BigDecimal(Long.MAX_VALUE);

bd;                           // 9223372036854775807

bd.add(new BigDecimal(1));    // 9223372036854775808

Même s'il est ajouté à la limite supérieure de «long», il ne déborde pas. Il est normal d'ajouter plus audacieusement.

bd.add(bd);                   // 18446744073709551614

Vous pouvez également ajouter des «fractions».

bd.add(new BigDecimal(0.5));  // 9223372036854775807.5

préféré? Qu'en est-il de l'erreur «fractionnaire» de?

BigDecimal bd = BigDecimal.ZERO;
BigDecimal x = new BigDecimal(0.01);
for (int i = 0; i < 100; i++) {
    bd = bd.add(x);
}

bd;    // 1.00000000000000002081668171172168513294309377670288085937500

C'est plus précis que «1.0000000000000007» de «double». (ToString est fait parce que je fais de mon mieux.)

Qu'en est-il de 10d / 3d, qui a une erreur dans double?

BigDecimal bd10 = new BigDecimal(10);
BigDecimal bd3  = new BigDecimal(3);

bd10.divide(bd3);    // ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

J'ai vu le mot «se terminer» dans le truc qui ressemble à une figurine de Ben, et je suis en colère que ce ne soit pas une fraction finie.

Il semble que la valeur avec l'erreur ne sera pas conservée avec l'erreur. Cela semble inutile si vous ne spécifiez pas s'il faut couper ou arrondir.

bd10.divide(bd3, RoundingMode.FLOOR) // 3

bd10.divide(bd3, RoundingMode.CEILING) // 4

BigInteger Ce mec est facile. C'est un «grand décimal» qui ne peut pas gérer les «fractions».

BigInteger bi = BigInteger.valueOf(Long.MAX_VALUE);

bi;            // 9223372036854775807

bi.add(bi);    // 18446744073709551614

BigInteger n'a pas de méthode de génération qui vous permet de passer une fraction comme 0.5, donc c'est juste cela par rapport à BigDecimal.

Tout va bien maintenant. Pas effrayant.

À part: destructif / non destructif

Au fait, si cela ressemble à java, n'avez-vous pas envie de le détruire avec ʻadd`? C'est comme «List # add».

Cependant, si vous comprenez que vous pouvez réallouer de la mémoire à chaque fois que vous ajoutez`, il est facile de penser que vous créez une instance non destructive et différente à chaque fois. (Cela dépend de la méthode d'implémentation, donc il peut être immuable, mais il peut être mutable.)

Résumé

Cela a été un long article, mais il n'y a que trois points principaux d'expression numérique en java que j'ai ressenti après l'avoir essayé!

C'est tout! La différence entre ʻint et ʻInteger est que je ferai de mon mieux pour étudier java plutôt que l'expression numérique!

Bref, j'ai beaucoup appris. J'étais parfaitement conscient de la façon dont je venais habituellement.

Et que faire si vous comprenez cela, c'est que vous voulez le séparer de la logique du domaine, alors créez un objet de valeur et cachez-le! Je le comprends exactement, donc je ne l'utilise pas dans mon travail quotidien (implémentation de domaine)! Quel paradoxe!

Recommended Posts

Comprendre la différence entre int et Integer et BigInteger en java et float et double
Différence entre int et Integer en Java
[Java] Comprendre la différence entre List et Set
Différence entre final et immuable en Java
[iOS] Comprendre la différence entre le cadre et les limites
Différence entre next () et nextLine () dans Java Scanner
Différences entre les classes et les instances dans Ruby
[Java] Différence entre statique final et final dans les variables membres
[JAVA] Quelle est la différence entre interface et abstract? ?? ??
[Java] Différence entre == et égal
[Ruby] Différence entre obtenir et publier
Obtenez le résultat de POST en Java
Comprenez en 3 minutes! Une explication très approximative de la différence entre session et cookie
Différence entre Java et JavaScript (comment trouver la moyenne)
[Java] Vérifiez la différence entre orElse et orElseGet avec IntStream
Pensez aux différences entre les fonctions et les méthodes (en Java)
L'évaluation des courts-circuits est-elle vraiment rapide? Différence entre && et & en Java
[JAVA] Différence entre abstrait et interface
[Java] Différence entre array et ArrayList
[Java] Différence entre fermable et fermable automatiquement
[Java] Différence entre StringBuffer et StringBuilder
[Java] Différence entre longueur, longueur () et taille ()
Sortie de la différence entre chaque champ de deux objets en Java
[Java] Quelle est la différence entre form, entity et dto? [Haricot]
Facile à comprendre la différence entre la méthode d'instance Ruby et la méthode de classe.
[Pour les débutants] Différence entre Java et Kotlin
Différence entre getText () et getAttribute () de Selenium
À propos de la différence entre irb et pry
Différence entre "|| =" et "instance_variable_defined?" Dans Ruby memo
Différence entre les listes d'arry et les listes liées en Java
[Rails] Différence de comportement entre delegate et has_many-through dans le cas de one-to-one-to-many
Concernant les modificateurs transitoires et la sérialisation en Java
[Java] Différence entre equals et == dans une chaîne de caractères qui est un type de référence
[Rails / Active Record] À propos de la différence entre créer et créer!
Quelle est la différence entre SimpleDateFormat et DateTimeFormatter? ??
[Java] Comprenez en 10 minutes! Tableau associatif et HashMap
Résumer les différences entre l'écriture C # et Java
Distinguer les nombres positifs et négatifs en Java
[Java] Différence entre "variable finale" et "objet immuable"
[Java] Remarque sur la différence entre le jugement d'équivalence et le jugement d'égalité lors de la comparaison de classes String
[Ruby] J'ai réfléchi à la différence entre each_with_index et each.with_index
[Rails] J'ai étudié la différence entre les ressources et les ressources
Écrivez ABNF en Java et transmettez l'adresse e-mail
Veuillez noter la division (division) de java kotlin Int et Int
Quelle est la différence entre System Spec et Feature Spec?
Concernant la différence entre les trois Timeouts dans HttpClient de Java
Différence entre nouveau et créer dans le contrôleur d'action Rais
Calculer la différence entre les nombres dans un tableau Ruby
[Rails] Quelle est la différence entre la redirection et le rendu?
Comparez la différence entre dockerfile avant et après docker-slim
Quelle est la différence entre ignorer et en attente? [RSpec]
[Swift] UITextField m'a appris la différence entre nil et ""
[Java débutant] Différence entre la longueur et la longueur () ~ Je ne sais pas ~
Différence entre vh et%
Différence entre i ++ et ++ i
Quelle est la différence entre les responsabilités de la couche domaine et de la couche application dans l’architecture onion [DDD]
Maintenant dans la troisième année, le malentendu que j'ai remarqué est la différence entre la méthode equals et ==