Warum hat Java Grundelemente für unterschiedliche Größenangaben?

20

In Java gibt es primitive Typen für byte, short, intund longund die gleiche Sache für floatund double. Warum muss eine Person festlegen, wie viele Bytes für einen primitiven Wert verwendet werden sollen? Konnte die Größe nicht einfach dynamisch bestimmt werden, abhängig davon, wie groß die übergebene Zahl war?

Ich kann mir zwei Gründe vorstellen:

  1. Das dynamische Einstellen der Datengröße würde bedeuten, dass sich die Daten auch dynamisch ändern müssen. Dies kann möglicherweise zu Leistungsproblemen führen.
  2. Vielleicht möchte der Programmierer nicht, dass jemand eine größere Zahl als eine bestimmte Größe verwenden kann, und dies ermöglicht es ihm, diese zu begrenzen.

Ich denke immer noch, dass es eine Menge zu gewinnen gab, wenn man einfach eine Single intund einen floatTyp verwendete. Gab es einen bestimmten Grund, warum Java sich entschied, diesen Weg nicht zu gehen?

yitzih
quelle
4
Ich möchte Downvotern hinzufügen, dass diese Frage mit einer Frage verbunden ist, die Compiler-Forscher zu beantworten suchen .
rwong
Wenn Sie also eine Zahl hinzufügen, denken Sie, dass der Typ dynamisch geändert werden sollte? Möchte ich überhaupt, dass der Typ geändert wird? Wenn die Nummer als intUnknown initialisiert ist, ist alpha = a + b; bekommen Sie das wäre ein wenig schwer für den Compiler. Warum ist das spezifisch für Java?
Paparazzo
@Paparazzi Es gibt bereits Programmiersprachen und Ausführungsumgebungen (Compiler, Interpreter usw.), in denen die Ganzzahl mit dynamischer Breite basierend auf der Größe des tatsächlichen Werts (z. B. dem Ergebnis der Additionsoperation) gespeichert wird. Die Konsequenzen sind: Der auf der CPU auszuführende Code wird komplizierter; Die Größe dieser Ganzzahl wird dynamisch. Das Lesen einer Ganzzahl mit dynamischer Breite aus dem Speicher erfordert möglicherweise mehr als eine Auslösung. Strukturen (Objekte) und Arrays, die in ihren Feldern / Elementen Ganzzahlen mit dynamischer Breite enthalten, können ebenfalls eine dynamische Größe haben.
rwong
1
@tofro verstehe ich nicht. Senden Sie die Zahl einfach in einem beliebigen Format: Dezimal, Binär usw. Die Serialisierung ist ein völlig orthogonales Problem.
Gardenhead
1
@gardenhead Es ist orthogonal, ja, aber ... betrachten Sie nur den Fall, in dem Sie zwischen einem in Java geschriebenen Server und einem in C geschriebenen Client kommunizieren möchten. Natürlich kann dies mit einer dedizierten Infrastruktur gelöst werden. ZB gibt es Dinge wie developers.google.com/protocol-buffer . Aber dies ist ein großer Vorschlaghammer für die kleine Nuss, eine ganze Zahl über das Netzwerk zu übertragen. (Ich weiß, dies ist hier kein starkes Argument, aber vielleicht ein zu berücksichtigender Punkt - die Erörterung der Details würde den Rahmen der Kommentare sprengen.)
Marco13

Antworten:

16

Wie so viele Aspekte des Sprachdesigns kommt es zu einem Kompromiss zwischen Eleganz und Leistung (ganz zu schweigen von einem historischen Einfluss früherer Sprachen).

Alternativen

Es ist sicherlich möglich (und recht einfach), eine Programmiersprache zu erstellen, die nur einen einzigen Typ natürlicher Zahlen enthält nat. Fast alle Programmiersprachen, die für das akademische Studium verwendet werden (z. B. PCF, System F), haben diesen Typ mit einer einzigen Zahl, der, wie Sie vermutet haben, die elegantere Lösung ist. In der Praxis geht es beim Sprachdesign jedoch nicht nur um Eleganz. Wir müssen auch die Leistung berücksichtigen (inwieweit die Leistung berücksichtigt wird, hängt von der beabsichtigten Anwendung der Sprache ab). Die Aufführung umfasst sowohl zeitliche als auch räumliche Einschränkungen.

Raumbeschränkungen

Wenn Sie den Programmierer die Anzahl der Bytes im Voraus auswählen lassen, können Sie Speicherplatz in Programmen mit eingeschränktem Speicherplatz sparen. Wenn alle Ihre Zahlen unter 256 liegen, können Sie 8-mal so viele bytes wie longs verwenden oder den gespeicherten Speicher für komplexere Objekte verwenden. Der Java-Standardanwendungsentwickler muss sich nicht um diese Einschränkungen kümmern, sie treten jedoch auf.

Effizienz

Auch wenn wir den Speicherplatz ignorieren, werden wir immer noch von der CPU eingeschränkt, die nur Befehle enthält, die mit einer festen Anzahl von Bytes arbeiten (8 Bytes bei einer 64-Bit-Architektur). Dies bedeutet, dass selbst die Bereitstellung eines einzelnen 8-Byte- longTyps die Implementierung der Sprache erheblich einfacher machen würde als die Verwendung eines unbegrenzten natürlichen Zahlentyps, da arithmetische Operationen direkt auf eine einzelne zugrunde liegende CPU-Anweisung abgebildet werden können. Wenn Sie dem Programmierer erlauben, beliebig große Zahlen zu verwenden, muss eine einzelne Rechenoperation einer Folge komplexer Maschinenbefehle zugeordnet werden, die das Programm verlangsamen würden. Dies ist Punkt (1), den Sie angesprochen haben.

Gleitkommatypen

Die bisherige Diskussion betraf nur ganze Zahlen. Gleitkommatypen sind ein komplexes Biest mit äußerst subtiler Semantik und Kantenfällen. So, obwohl wir leicht ersetzen könnten int, long, shortund bytemit einer einzigen natArt ist es nicht klar , was die Art des Gleitkommazahlen selbst ist . Offensichtlich sind es keine reellen Zahlen, da in einer Programmiersprache keine reellen Zahlen existieren können. Sie sind auch keine ganz rationalen Zahlen (obwohl es einfach ist, einen rationalen Typ zu erstellen, falls gewünscht). Grundsätzlich entschied sich IEEE für eine Art Annäherung an reelle Zahlen, und alle Sprachen (und Programmierer) sind seitdem mit ihnen festgefahren.

Endlich:

Vielleicht möchte der Programmierer nicht, dass jemand eine größere Zahl als eine bestimmte Größe verwenden kann, und dies ermöglicht es ihm, diese zu begrenzen.

Dies ist kein triftiger Grund. Erstens kann ich mir keine Situationen vorstellen, in denen Typen auf natürliche Weise numerische Grenzen kodieren könnten, ganz zu schweigen von den astronomisch geringen Chancen, dass die Grenzen, die der Programmierer erzwingen möchte, genau der Größe eines der primitiven Typen entsprechen.

Gartenkopf
quelle
2
Der eigentliche Schlüssel zur Tatsache, dass wir Floats haben, ist, dass wir dedizierte Hardware für sie haben
jk.
Auch das Codieren von numerischen Grenzen in einem Typ geschieht absolut in abhängig typisierten Sprachen und in geringerem Maße in anderen Sprachen, z. B. als Enummen
jk.
3
Aufzählungen sind nicht gleich Ganzzahlen. Aufzählungen sind nur eine Art der Verwendung von Summentypen. Die Tatsache, dass einige Sprachen Aufzählungen transparent als Ganzzahlen codieren, ist ein Sprachfehler und keine ausnutzbare Funktion.
Gardenhead
1
Ich kenne Ada nicht. Könnte ich ganze Zahlen auf einen beliebigen Typ beschränken, z type my_type = int (7, 2343).
Gardenhead
1
Ja. Die Syntax wäre: type my_type is range 7..2343
Devsman
9

Der Grund ist sehr einfach: Effizienz . In mehrfacher Hinsicht.

  1. Native Datentypen: Je genauer die Datentypen einer Sprache mit den zugrunde liegenden Datentypen der Hardware übereinstimmen, desto effizienter wird die Sprache. (Nicht in dem Sinne, dass Ihre Programme unbedingt effizient sein müssen, sondern in dem Sinne, dass Sie, wenn Sie wirklich wissen, was Sie tun, Code schreiben können, der so effizient ausgeführt wird, wie es die Hardware kann.) Die angebotenen Datentypen von Java entsprechen Bytes, Wörtern, Doppelwörtern und Vierfachwörtern der beliebtesten Hardware da draußen. Das ist der effizienteste Weg.

  2. Unberechtigter Overhead auf 32-Bit-Systemen: Wenn entschieden worden wäre, alles auf eine 64-Bit-Länge mit fester Größe abzubilden, hätte dies einen enormen Nachteil für 32-Bit-Architekturen zur Folge, die erheblich mehr Taktzyklen benötigen, um ein 64-Bit -System auszuführen. Bit-Operation als eine 32-Bit-Operation.

  3. Verschwendung von Arbeitsspeicher: Es gibt eine Menge Hardware, die in Bezug auf die Ausrichtung des Arbeitsspeichers nicht allzu wählerisch ist (die Intel x86- und x64-Architekturen sind Beispiele dafür), sodass ein Array von 100 Byte auf dieser Hardware nur 100 Byte Arbeitsspeicher belegen kann. Wenn Sie jedoch kein Byte mehr haben und stattdessen ein langes verwenden müssen, belegt dasselbe Array eine Größenordnung mehr Speicher. Und Byte-Arrays sind sehr verbreitet.

  4. Berechnen von Zahlengrößen: Ihre Vorstellung, die Größe einer Ganzzahl dynamisch zu bestimmen, je nachdem, wie groß die übergebene Zahl war, ist zu simpel. Es gibt keinen einzigen Punkt, an dem eine Zahl "übergeben" werden könnte. Die Berechnung, wie groß eine Zahl sein muss, muss zur Laufzeit für jede einzelne Operation durchgeführt werden, die möglicherweise ein Ergebnis einer größeren Größe erfordert: Jedes Mal, wenn Sie eine Zahl inkrementieren, jedes Mal, wenn Sie zwei Zahlen hinzufügen, jedes Mal, wenn Sie zwei multiplizieren Zahlen usw.

  5. Operationen mit Zahlen unterschiedlicher Größe: In der Folge würde es alle Operationen erschweren, Zahlen potenziell unterschiedlicher Größe im Speicher zu haben: Auch um zwei Zahlen einfach zu vergleichen, müsste die Laufzeit zunächst prüfen, ob beide zu vergleichenden Zahlen gleich sind Größe, und wenn nicht, passen Sie die Größe der kleineren an die Größe der größeren an.

  6. Operationen, die bestimmte Operandengrößen erfordern: Für bestimmte bitweise Operationen muss die Ganzzahl eine bestimmte Größe haben. Diese Operationen müssten emuliert werden, wenn sie keine vorgegebene spezifische Größe hätten.

  7. Overhead des Polymorphismus: Das Ändern der Größe einer Zahl zur Laufzeit bedeutet im Wesentlichen, dass sie polymorph sein muss. Dies bedeutet wiederum, dass es sich nicht um ein Grundelement mit fester Größe handeln kann, das dem Stapel zugewiesen wurde, sondern um ein Objekt, das dem Heap zugewiesen wurde. Das ist schrecklich ineffizient. (Lesen Sie noch einmal # 1 oben.)

Mike Nakis
quelle
6

Um zu vermeiden, dass die Punkte, die in anderen Antworten besprochen wurden, wiederholt werden, werde ich stattdessen versuchen, mehrere Perspektiven zu skizzieren.

Aus Sicht der Sprachgestaltung

  • Es ist sicherlich möglich, eine Programmiersprache und ihre Ausführungsumgebung zu entwerfen und zu implementieren, die automatisch die Ergebnisse von Ganzzahloperationen berücksichtigt, die nicht in die Maschinenbreite passen.
  • Es ist die Wahl des Sprachdesigners, solche Ganzzahlen mit dynamischer Breite als Standard-Ganzzahltyp für diese Sprache festzulegen.
  • Der Sprachdesigner muss jedoch die folgenden Nachteile berücksichtigen:
    • Die CPU muss mehr Code ausführen, was mehr Zeit in Anspruch nimmt. Es ist jedoch möglich, für den häufigsten Fall zu optimieren, in dem die Ganzzahl in ein einzelnes Maschinenwort passt. Siehe getaggte Zeigerdarstellung .
    • Die Größe dieser Ganzzahl wird dynamisch.
    • Das Lesen einer Ganzzahl mit dynamischer Breite aus dem Speicher erfordert möglicherweise mehr als eine Auslösung.
    • Strukturen (Objekte) und Arrays, die in ihren Feldern / Elementen Ganzzahlen mit dynamischer Breite enthalten, haben eine Gesamtgröße (belegt), die ebenfalls dynamisch ist.

Historische Gründe

Dies wird bereits in dem Wikipedia-Artikel über die Geschichte von Java und in der Antwort von Marco13 kurz besprochen .

Ich möchte darauf hinweisen, dass:

  • Sprachdesigner müssen zwischen einer ästhetischen und einer pragmatischen Denkweise jonglieren. Die ästhetische Denkweise möchte eine Sprache entwerfen, die nicht für bekannte Probleme wie Integer-Überläufe anfällig ist. Die pragmatische Denkweise erinnert den Designer daran, dass die Programmiersprache gut genug sein muss, um nützliche Softwareanwendungen zu implementieren und mit anderen Softwareteilen zusammenzuarbeiten, die in verschiedenen Sprachen implementiert sind.
  • Programmiersprachen, die beabsichtigen, Marktanteile älterer Programmiersprachen zu gewinnen, sind möglicherweise eher pragmatisch. Eine mögliche Folge ist, dass sie eher bereit sind, vorhandene Programmierkonstrukte und -stile aus diesen älteren Sprachen zu übernehmen oder auszuleihen.

Effizienzgründe

Wann ist Effizienz wichtig?

  • Wenn Sie beabsichtigen, eine Programmiersprache als geeignet für die Entwicklung von Großanwendungen zu bewerben.
  • Wenn Sie an Millionen und Abermillionen von Kleinteilen arbeiten müssen, bei denen sich jedes bisschen Effizienz summiert.
  • Wenn Sie mit einer anderen Programmiersprache konkurrieren müssen, muss Ihre Sprache eine anständige Leistung erbringen - es muss nicht die beste sein, aber es hilft sicherlich, in der Nähe der besten Leistung zu bleiben.

Speichereffizienz (im Speicher oder auf der Festplatte)

  • Der Computerspeicher war einst eine knappe Ressource. In jenen alten Tagen war die Größe der Anwendungsdaten, die von einem Computer verarbeitet werden konnten, durch die Größe des Computerspeichers begrenzt, obwohl dies möglicherweise durch geschickte Programmierung umgangen werden konnte (deren Implementierung mehr kosten würde).

Effizienz der Ausführung (innerhalb der CPU oder zwischen CPU und Speicher)

  • Bereits in der Antwort von gardenhead besprochen .
  • Wenn ein Programm sehr große Arrays mit kleinen Zahlen verarbeiten muss, die nacheinander gespeichert werden, wirkt sich die Effizienz der In-Memory-Darstellung direkt auf die Ausführungsleistung aus, da die große Datenmenge den Durchsatz zwischen CPU und Speicher zu einem Engpass werden lässt. In diesem Fall bedeutet dichteres Packen von Daten, dass ein einzelner Cache-Zeilenabruf mehr Datenelemente abrufen kann.
  • Diese Argumentation gilt jedoch nicht, wenn die Daten nicht nacheinander gespeichert oder verarbeitet werden.

Die Notwendigkeit, dass Programmiersprachen eine Abstraktion für kleine ganze Zahlen bieten, auch wenn sie auf bestimmte Kontexte beschränkt sind

  • Diese Anforderungen ergeben sich häufig bei der Entwicklung von Softwarebibliotheken, einschließlich der sprachspezifischen Standardbibliotheken. Nachfolgend sind einige solcher Fälle aufgeführt.

Interoperabilität

  • Häufig müssen Programmiersprachen höherer Ebenen mit dem Betriebssystem oder mit Softwarekomponenten (Bibliotheken) interagieren, die in anderen Sprachen niedrigerer Ebenen geschrieben wurden. Diese untergeordneten Sprachen kommunizieren häufig unter Verwendung von "Strukturen" , bei denen es sich um eine starre Spezifikation des Speicherlayouts eines Datensatzes handelt, der aus Feldern unterschiedlicher Typen besteht.
  • Beispielsweise muss in einer höheren Sprache möglicherweise angegeben werden, dass eine bestimmte Fremdfunktion ein charArray der Größe 256 akzeptiert. (Beispiel.)
  • Einige von Betriebssystemen und Dateisystemen verwendete Abstraktionen erfordern die Verwendung von Byteströmen.
  • Einige Programmiersprachen bieten Dienstprogrammfunktionen an (z. B. BitConverter), um das Packen und Entpacken von schmalen Ganzzahlen in Bit- und Byte-Streams zu erleichtern.
  • In diesen Fällen müssen die engeren Integer-Typen keine in die Sprache eingebauten primitiven Typen sein. Stattdessen können sie als Bibliothekstyp bereitgestellt werden.

String-Behandlung

  • Es gibt Anwendungen, deren Hauptentwurfszweck darin besteht, Zeichenfolgen zu bearbeiten. Daher ist die Effizienz des String-Handlings für diese Arten von Anwendungen wichtig.

Dateiformatbehandlung

  • Viele Dateiformate wurden mit einer C-ähnlichen Einstellung entworfen. Daher war die Verwendung von Feldern mit schmaler Breite weit verbreitet.

Wünschbarkeit, Softwarequalität und Verantwortung des Programmierers

  • Für viele Arten von Anwendungen ist die automatische Erweiterung ganzer Zahlen eigentlich nicht wünschenswert. Weder Sättigung noch Umgriff (Modul).
  • Viele Arten von Anwendungen profitieren von der expliziten Angabe der größten zulässigen Werte durch den Programmierer an verschiedenen kritischen Punkten in der Software, z. B. auf API-Ebene.

Stellen Sie sich das folgende Szenario vor.

  • Eine Software-API akzeptiert eine JSON-Anfrage. Die Anforderung enthält ein Array von untergeordneten Anforderungen. Die gesamte JSON-Anforderung kann mit dem Deflate-Algorithmus komprimiert werden.
  • Ein böswilliger Benutzer erstellt eine JSON-Anforderung, die eine Milliarde untergeordneter Anforderungen enthält. Alle untergeordneten Anforderungen sind identisch. Der böswillige Benutzer beabsichtigt, dass das System einige CPU-Zyklen brennt und dabei unnütze Arbeit leistet. Aufgrund der Komprimierung werden diese identischen untergeordneten Anforderungen auf eine sehr kleine Gesamtgröße komprimiert.
  • Es ist offensichtlich, dass ein vordefinierter Grenzwert für die komprimierte Größe der Daten nicht ausreicht. Stattdessen muss die API ein vordefiniertes Limit für die Anzahl der in ihr enthaltenen untergeordneten Anforderungen und / oder ein vordefiniertes Limit für die deflationierte Größe der Daten festlegen.

Häufig muss für diesen Zweck Software entwickelt werden, mit der sich viele Größenordnungen sicher skalieren lassen, wobei die Komplexität zunimmt. Es kommt nicht automatisch, auch wenn das Problem des Überlaufs von Ganzzahlen beseitigt ist. Dies schließt sich zu einem Kreis, der die Perspektive des Sprachdesigns beantwortet: Oft ist Software, die sich weigert, eine Arbeit auszuführen, wenn ein unbeabsichtigter ganzzahliger Überlauf auftritt (durch Auslösen eines Fehlers oder einer Ausnahme), besser als Software, die automatisch astronomisch große Operationen ausführt.

Dies bedeutet die Perspektive des OP,

Warum muss eine Person festlegen, wie viele Bytes für einen primitiven Wert verwendet werden sollen?

das ist nicht richtig. Es sollte dem Programmierer gestattet sein und manchmal erforderlich sein, die maximale Größe anzugeben, die ein ganzzahliger Wert in kritischen Teilen der Software annehmen kann. Wie die Antwort von gardenhead zeigt, sind die natürlichen Grenzen primitiver Typen für diesen Zweck nicht nützlich. Die Sprache muss Programmierern die Möglichkeit geben, Größenangaben zu machen und solche Grenzwerte durchzusetzen.

rwong
quelle
2

Es kommt alles von Hardware.

Ein Byte ist die kleinste adressierbare Speichereinheit auf den meisten Hardwarekomponenten.

Jeder Typ, den Sie gerade erwähnt haben, besteht aus mehreren Bytes.

Ein Byte besteht aus 8 Bits. Damit können Sie 8 Boolesche Werte ausdrücken, aber Sie können nicht immer nur einen nachschlagen. Sie adressieren 1, Sie adressieren alle 8.

Früher war es so einfach, aber dann sind wir von einem 8-Bit-Bus zu einem 16-, 32- und jetzt 64-Bit-Bus übergegangen.

Das heißt, solange wir noch auf Byte-Ebene adressieren können, können wir kein einzelnes Byte mehr aus dem Speicher abrufen, ohne die benachbarten Bytes abzurufen.

Angesichts dieser Hardware haben sich die Sprachentwickler dafür entschieden, Typen auszuwählen, die es uns ermöglichen, Typen auszuwählen, die zur Hardware passen.

Sie können behaupten, dass ein solches Detail entfernt werden kann und sollte, insbesondere in einer Sprache, die auf jeder Hardware ausgeführt werden soll. Dies hätte versteckte Leistungsprobleme, aber Sie könnten Recht haben. Das ist einfach nicht so passiert.

Java versucht dies tatsächlich. Bytes werden automatisch zu Ints hochgestuft. Eine Tatsache, die Sie verrückt macht, wenn Sie zum ersten Mal versuchen, ernsthafte Änderungen daran vorzunehmen.

Warum hat es nicht gut funktioniert?

Das große Verkaufsargument von Java war damals, dass man sich mit einem bekannten guten C-Algorithmus hinsetzen, es in Java tippen und mit kleinen Optimierungen würde es funktionieren. Und C ist sehr nah an der Hardware.

Das beizubehalten und die Größe von integralen Typen zu abstrahieren, funktionierte einfach nicht zusammen.

Also könnten sie haben. Sie haben es einfach nicht getan.

Vielleicht möchte der Programmierer nicht, dass jemand eine größere Zahl als eine bestimmte Größe verwenden kann, und dies ermöglicht es ihm, diese zu begrenzen.

Das ist gültiges Denken. Dafür gibt es Methoden. Die Klemmfunktion für einen. Eine Sprache könnte so weit gehen, beliebige Grenzen in ihre Typen zu setzen. Und wenn diese Grenzen zur Kompilierungszeit bekannt sind, können Sie die Speicherung dieser Zahlen optimieren.

Java ist einfach nicht diese Sprache.

kandierte_orange
quelle
" Eine Sprache könnte so weit gehen, dass sie willkürliche Schranken in ihre Typen schreibt ". Und tatsächlich hat Pascal eine Form davon mit Unterbereichstypen.
Peter Taylor
1

Wahrscheinlich ist ein wichtiger Grund, warum diese Typen in Java existieren, einfach und bedenklich nicht technisch:

C und C ++ hatten auch diese Typen!

Obwohl es schwierig ist, einen Beweis dafür zu liefern, gibt es zumindest einige starke Beweise: Die Oak Language Specification (Version 0.2) enthält die folgende Passage:

3.1 Integer-Typen

Ganzzahlen in der Sprache Oak ähneln denen in C und C ++, mit zwei Ausnahmen: Alle Ganzzahlentypen sind maschinenunabhängig, und einige der traditionellen Definitionen wurden geändert, um Änderungen in der Welt seit Einführung von C Rechnung zu tragen. Die vier Integer-Typen haben eine Breite von 8, 16, 32 und 64 Bit und sind vorzeichenbehaftet, sofern der unsignedModifikator kein Präfix enthält .

Die Frage könnte also lauten:

Warum wurden Short, Int und Long in C erfunden?

Ich bin mir nicht sicher, ob die Antwort auf die Brieffrage im Kontext der hier gestellten Frage zufriedenstellend ist. In Kombination mit den anderen Antworten wird jedoch möglicherweise klar, dass es von Vorteil sein kann, diese Typen zu haben (unabhängig davon, ob ihre Existenz in Java nur ein Erbe von C / C ++ ist).

Die wichtigsten Gründe, die mir einfallen, sind:

  • Ein Byte ist die kleinste adressierbare Speichereinheit (wie CandiedOrange bereits erwähnt). A byteist der elementare Datenbaustein, der aus einer Datei oder über das Netzwerk gelesen werden kann. Einige explizite Darstellungen sollten vorhanden sein (und es gibt sie in den meisten Sprachen, auch wenn sie manchmal in Verkleidung erscheinen).

  • In der Praxis ist es zwar sinnvoll, alle Felder und lokalen Variablen mit einem einzigen Typ darzustellen und diesen Typ aufzurufen int. Zu Stackoverflow gibt es eine verwandte Frage: Warum verwendet die Java-API int anstelle von short oder byte? . Wie ich dort in meiner Antwort erwähnt habe, ist eine Rechtfertigung für die Verwendung der kleineren Typen ( byteund short), dass Sie Arrays dieser Typen erstellen können: Java hat eine Darstellung von Arrays, die immer noch ziemlich "hardwarenah" ist. Im Gegensatz zu anderen Sprachen (und im Gegensatz zu Arrays von Objekten wie einem Integer[n]Array) ist ein int[n]Array keine Sammlung von Referenzen, bei denen die Werte über den gesamten Heap verteilt sind. Stattdessen es wird in der Praxis ein fortlaufender Block vonn*4Bytes - Ein Speicherblock mit bekannter Größe und Datenlayout. Wenn Sie die Wahl haben, 1000 Bytes in einer Sammlung von Objekten mit beliebig großen Ganzzahlen zu speichern, oder in einem Objekt byte[1000](das 1000 Bytes benötigt), kann letzteres tatsächlich Speicherplatz sparen. (Einige andere Vorteile sind möglicherweise subtiler und werden nur dann offensichtlich, wenn Java mit nativen Bibliotheken verbunden wird.)


In Bezug auf die Punkte, die Sie speziell gefragt haben:

Konnte die Größe nicht einfach dynamisch bestimmt werden, abhängig davon, wie groß die übergebene Zahl war?

Das dynamische Einstellen der Datengröße würde bedeuten, dass sich die Daten auch dynamisch ändern müssen. Dies kann möglicherweise zu Leistungsproblemen führen.

Es wäre wahrscheinlich möglich, die Größe von Variablen dynamisch festzulegen, wenn man in Betracht ziehen würde, eine völlig neue Programmiersprache von Grund auf neu zu entwerfen. Ich bin kein Experte für Compilerkonstruktionen, denke aber, dass es schwierig ist, Sammlungen mit sich dynamisch ändernden Typen sinnvoll zu verwalten - insbesondere, wenn Sie eine stark typisierte Sprache haben. Es käme also wahrscheinlich darauf an, dass alle Zahlen in einem "generischen Datentyp mit willkürlicher Genauigkeit" gespeichert würden, was sich sicherlich auf die Leistung auswirken würde. Natürlich gibt es Programmiersprachen, die stark typisiert sind und / oder Nummerntypen mit willkürlicher Größe anbieten, aber ich glaube nicht, dass es eine echte Allzweck-Programmiersprache gibt, die diesen Weg gegangen ist.


Randnotizen:

  • Sie haben sich vielleicht über den unsignedModifikator gewundert, der in der Oak-Spezifikation erwähnt wurde. In der Tat enthält es auch eine Bemerkung: " unsignedist noch nicht implementiert; es könnte niemals sein." . Und sie hatten recht.

  • Sie wundern sich nicht nur, warum C / C ++ überhaupt diese verschiedenen Integer-Typen hat, sondern Sie wundern sich auch, warum sie sie so schrecklich durcheinandergebracht haben, dass Sie nie wissen, wie viele Bits eine inthat. Die Begründungen hierfür beziehen sich normalerweise auf die Leistung und können an anderer Stelle nachgeschlagen werden.

Marco13
quelle
0

Es zeigt sicherlich, dass Sie noch nicht über Leistung und Architekturen unterrichtet wurden.

  • Erstens kann nicht jeder Prozessor mit den großen Typen umgehen, daher müssen Sie die Einschränkungen kennen und damit arbeiten.
  • Zweitens bedeuten kleinere Typen mehr Leistung bei der Ausführung von Vorgängen.
  • Auch die Größe spielt eine Rolle. Wenn Sie Daten in einer Datei oder Datenbank speichern müssen, wirkt sich die Größe sowohl auf die Leistung als auch auf die endgültige Größe aller Daten aus. Nehmen wir beispielsweise an, Sie haben eine Tabelle mit 15 Spalten und am Ende mehrere Millionen von Datensätzen. Der Unterschied zwischen der Auswahl einer nach Bedarf kleinen Größe für jede Spalte oder der Auswahl des größten Typs ist ein Unterschied zwischen den möglichen Datenmengen und der Zeit für die Ausführung von Vorgängen.
  • Dies gilt auch für komplexe Berechnungen, bei denen die Größe der verarbeiteten Daten einen großen Einfluss hat, z. B. bei Spielen.

Wenn Sie die Bedeutung der Datengröße ignorieren, wirkt sich dies immer auf die Leistung aus. Sie müssen so viele Ressourcen wie nötig verwenden, aber nicht mehr, immer!

Das ist der Unterschied zwischen einem Programm oder System, das wirklich einfache Dinge tut und unglaublich ineffizient ist, viele Ressourcen erfordert und die Verwendung dieses Systems wirklich kostspielig macht. oder ein System, das viel leistet, aber schneller läuft als andere und das sehr billig zu betreiben ist.

Nestor Mata Cuthbert
quelle
0

Dafür gibt es ein paar gute Gründe

(1) Während die Speicherung von einer Byte-Variablen gegenüber einer Länge unbedeutend ist, ist die Speicherung von Millionen in einem Array sehr wichtig.

(2) "Hardware native" Arithmetik auf der Grundlage bestimmter ganzzahliger Größen kann sehr viel effizienter sein, und für einige Algorithmen auf einigen Plattformen kann dies wichtig sein.

ddyer
quelle