Java Variabeln und ihre Grenzen ( speziell Float)

Tockra

Lt. Commander
Registriert
Dez. 2008
Beiträge
1.063
Hallo Leute,

Da ich gerade "Java ist auch eine Insel lese", habe ich eine kleine Textstelle gefunden, die mich verwundert:
http://openbook.galileocomputing.de/javainsel/javainsel_02_003.html#dodtpba664243-0cd9-4f96-b1d7-63063559438b 2.3.4 schrieb:
Hinweis
Der Datentyp float ist mit 4 Byte, also 32 Bit, ein schlechter Scherz. Der Datentyp double geht mit 64 Bit ja gerade noch, wobei in Hardware eigentlich 80 Bit üblich sind.

Da ich gelesen habe, dass die Grenzen von Float
1,40239846E-45f ... 3,40282347E+38f
sind, war ich etwas verwundert, da diese doch so witzigen Grenzen in meinem Auge sehr groß sind bzw. genau!?




Außerdem wurde an anderen Stellen erwähnt, dass Byte und Short sehr wenig gebraucht werden.
Nun frage ich mich, ob man immer short und byte nutzen sollte, wenn man weiß, dass die Variabel sowieso nicht über die Grenzen 2 hoch 7 oder 2 hoch 15 hinausgehen werden, oder kann man in solchen Fällen auch ohne groß nachzudenken int nehmen?

Gruß Tim
 
Ich kann Dir erstmal nur den zweiten Teil der Frage beantworten.

Im Grunde ist es heute ziemlich egal, ob Du die größte oder die passendste Variable nimmst. Du kannst für jede zweistellige Zahl auch ein LONG nehmen, verbrauchst halt mehr Speicher, aber davon hat heute sowieso jeder mehr als genug.

Wichtiger ist sowas, wenn Du mit extrem wenig Ressourcen auskommen mußt oder das Programm extrem riesige Dimensionen annimmt.
 
Ich weiß zwar nicht, was der Autor hat, aber 32 Bit für ein Float (Single) ist doch normal und entspricht der IEEE 754 Norm. Gleitkommazahlen werden nämlich anders abgebildet, als Ganzzahlen.
http://de.wikipedia.org/wiki/Gleitkommazahl#Interne_Darstellung

Der Autor geht aber wohl von der Gleitkommaeinheit aus, die in der Tat mit einer Genauigkeit von 80 Bit oder mehr, arbeiten. Letzendlich spielt bei Gleitkommazahlen aber nicht die maximal größte zu speichernde Zahl eine Rolle, sondern die Genauigkeit.
 
Zuletzt bearbeitet:
Die Frage mit float versteh ich nicht.

Und short und byte werden auch recht selten verwendet. deine JavaVM erledigt die Speicherverwaltung ja für dich. Speicher kostet heutzutage so oder so nichtsmehr. Ich kann mir gut vorstellen dass man short und byte eher auf mobilen Geräten verwendet, da dort der Speicherplatz sparsam verwaltet werden sollte. Sollange du für den PC programmierst, würd ich mir da kein Kopf machen.

Edit: zu spät :>
 
Er hat schon recht, float ist wirklich relativ ungenau. Man muss bei Vergleichen schon aufpassen und oft werden deltas/epsilons verwendet.

Klar am PC ist das heutzutage relativ egal, aber wenn man extrem performante Anwendungen wie Spiele o.ä., führt kein Weg an Optimierung gewisser Stellen vorbei. Und bei großen Datensätzen ebenfalls. Selbes gilt Geräte mit wenig Speicher oder anderen Einschränkungen.

Zusammenfassend gesagt: Normalerweise ist die Verwendung eher unwichtig, allerdings würde ich mich vor so Schwachsinn schützen wie jetzt in jedem Fall den größtmöglichen Typ zu verwenden nur weil das mal jemand empfohlen hat. Ich würde das nutzen das nötig ist und vorher überlegen, wofür das gebraucht wird. :)

PS: Ein schlechter Scherz ist float außerdem auch nicht. für viele Dinge reicht er einfach. Ist ja nicht so, dass da bei der IEEE alle doof sind, sondern früher erstmal einfach weniger technisch möglich war.
 
Zuletzt bearbeitet:
Wenn du effizient Programmierst, dann nimmst du natürlich den kleinstmöglichen, aber in jeder Situation ausreichenden Typ. Allerdings, wie gesagt, heute nicht mehr so wichtig.
 
@SO MANCHEN:

EINFACH KEINEN SINN FÜR DIE NUTZUNG VON RESSOURCEN
HOCH LEBE DIE HIRNLOSE VERSCHWENDUNG
ZUM GLÜCK GIBT ES VIEL SPEICHER DER DIE UNFÄHIGKEIT KASCHIERT


PHP:
import java.lang.reflect.Field;

import sun.misc.Unsafe;

public class Align
{
	int dummy;

	private static Unsafe unsafe;

	boolean boolean_1;
	boolean boolean_2;

	byte byte_1;
	byte byte_2;

	short short_1;
	short short_2;

	int int_1;
	int int_2;

	long long_1;
	long long_2;

	float float_1;
	float float_2;

	double double_1;
	double double_2;

	String string_1;
	String string_2;

	Align align_1;
	Align align_2;


	/**
	 * 
	 */
	public static void foo( String type )
	{
		try
		{
			long offset_1 = ( unsafe.objectFieldOffset( Align.class.getDeclaredField( type + "_1" ) ) );
			long offset_2 = ( unsafe.objectFieldOffset( Align.class.getDeclaredField( type + "_2" ) ) );

			System.out.println( type + "\t" + ( offset_2 - offset_1 ) );
		}
		catch (NoSuchFieldException | SecurityException e )
		{
			System.out.println( e.toString() );
		}
	}


	/**
	 * 
	 */
	public static void main( String[] args )
	{
		unsafe = getUnsafeInstance();

		if( unsafe != null )
		{
			Align.foo( "boolean" );
			Align.foo( "byte" );
			Align.foo( "short" );
			Align.foo( "int" );
			Align.foo( "long" );
			Align.foo( "float" );
			Align.foo( "double" );

			Align.foo( "string" );
			Align.foo( "align" );
		}
	}
	
	/**
	 * 
	 */
	public static Unsafe getUnsafeInstance()
	{
		 try
		 {
			 Field field = Unsafe.class.getDeclaredField( "theUnsafe" );
	
			 field.setAccessible( true );
	
			 Unsafe unsafe =  ( Unsafe ) field.get( Unsafe.class );

			 if( unsafe != null )
				 return ( unsafe );
		 }
		 catch( Exception e )
		 {
		 }

		 return ( null );
	}
}


Das sollte glaube ich deine Letzte Frage beantworten:
( 64Bit Os: selbst java achtet intern auf die Platzbelegung also macht es mehr als Sinn auf den Typ zu achten )
 
Zuletzt bearbeitet:
Man sollte dennoch darauf achten, die richtigen Typ zunehmen und nicht gleich von klein auf mit den Schlampen anfangen.
In Java mag es vllt. nicht ganz so extrem sein, aber in anderen Sprachen vllt. nicht mehr und, wenn du da keinen automatischen Aufräumer( GC ) hast und da Variablenleichen rumliegen... kann es ganz schön unschön werden.
 
DasBoeseLebt schrieb:
In Java mag es vllt. nicht ganz so extrem sein, aber in anderen Sprachen vllt. nicht mehr und, wenn du da keinen automatischen Aufräumer( GC ) hast und da Variablenleichen rumliegen... kann es ganz schön unschön werden.

Daß man mit Systemresourcen nicht sinnlos verschwenderisch umgehen soll verstehe ich ja noch, aber was hat das Vorhandensein oder Nichtvorhandensein eines Garbage Collectors damit zu tun, ob man zur Darstellung einer Zahl nun den kleinstmöglich passenden oder einen breiteren Datentyp verwendet?

Außerdem, wenn man nicht gerade ein Array mit einer Million Zahlen im Speicher liegen hat (in diesem Fall kann ein kleinerer Datentyp tatsächlich einen spürbaren Unterschied machen) sondern nur mal eben mit ein paar Variablen hantiert, ist man üblicherweise mit dem Datentyp am schnellsten unterwegs, dessen Breite der eines Maschinenwortes entspricht.
 
Glaub eher ein Halbes Word weil z.B: bei einer Addition ganz in Register ohne Überlauf passt. ;)
 
@BadMadMax:
Na ja, dafür muss man extra Takt einlegen, um ihn wieder abzuschneiden.

@Topic:
Ich verwende bei einmaligen Berechnungen gerne mal double, einfach weils genauer ist und dort die Geschwindigkeitseinbußen nicht wehtun.
Aber alles, was von der Geschwindigkeit einen spürbaren Unterschied ergeben kann, wird entweder mit int gerechnet (bei ganzzahlen hat man keine Rundungsprobleme) oder mit floats. Bspw. können viele Grafikkarten nur mit floats rechnen, dafür aber sehr schnell.

Das mit den Bits: Eigentlich sollte die FPU gar nicht mehr verwendet werden sondern nur noch die SSE Einheiten, die arbeiten entweder mit float (SSE1) oder mit double (SSE3).
 
Na solange du keine Preise mit Floats berechnest... Das kann übel nach hinten losgehen. *G*

Man sollte durchaus halbwegs den passenden Datentyp nutzen. Nur weil Speicherplatz nicht mehr hochgradig kritisch ist heißt das nicht, dass man ihn verschwenden sollte. Gibt ja alles trotzdem ein Geschwindigkeitszuwachs, und schnell bediente Kunden sind zufriedene Kunden.
 
antred schrieb:
..aber was hat das Vorhandensein oder Nichtvorhandensein eines Garbage Collectors damit zu tun, ob man zur Darstellung einer Zahl nun den kleinstmöglich passenden oder einen breiteren Datentyp verwendet?

Wenn man vergisst den Speicher wieder freizugeben :p
 
wenn man vergisst speicher wieder freizugeben ist das aber ein anderes problem xD

generell kann man aber sagen das man mit einem int für ganzzahlen und einen double für kommazahlen gut bedient ist...

wenn man mikrocontroller oder sehr hardwarenahe programmiert, bzw echtzeitanwendungen dann spielen datentypen gleich wieder eine ganz andere rolle... dort solltest du definitiv keinen platz verschwenden...
 
DasBoeseLebt schrieb:
Wenn man vergisst den Speicher wieder freizugeben :p

Wie Xetoxyc schon anmerkte, ist das ein völlig anderes Problem. ;)

Übrigens kannst du mit einem GC genau so Speicherlecks produzieren wie ohne GC. Der GC kann meines Wissens nur das wegräumen, was nicht mehr referenziert wird. Wenn du aber vergißt, nicht mehr benötigte Objekte zu "ent-referenzieren" (mir fällt im Moment kein passenders Wort ein :p), kann der GC auch nix machen.

Das ist übrigens der Grund, weshalb ich dieses blinde Vertrauen auf den GC noch nie verstanden habe. Bitte korregiert mich, falls ich hier was falsches erzählt habe.
 
antred schrieb:
Übrigens kannst du mit einem GC genau so Speicherlecks produzieren wie ohne GC. Der GC kann meines Wissens nur das wegräumen, was nicht mehr referenziert wird. .
Das ist so nicht ganz richtig.
Es wird je nach Sprache zwischen starken Referenzen und schwachen Referenzen unterschieden (in Java seit 1.2), Schwache können gelöscht werden.

Das nur mal zur Vollständigkeit!

Jedoch ... es stimmt, wenn man Leichen rumliegen hat, hat man schon vorher i-wie nicht ganz sauber gearbeitet. :(
 
Das ist korrekt so, antred. Ich schreite auch immer ein, wenn mal wieder jemand verbreitet dank GC bräuchte man sich um nichts mehr kümmern.

Zum Thema - wenn es sich um riesige multidimensionale Arrays handelt, dann sollte man (vor allem für embedded/mobile-Zeug) den kleinstmöglichen und hinreichend großen Typ wählen.
Wenn es um einzelne Klassenattribute oder lokale Variablen geht, dann handelt man sich mit solchen premature optimizations mehr Ärger ein, als die Sache wert ist. Völlig unnötig meiner Meinung nach.

In der VM geschieht ohnehin dermaßen viel Voodoo, dass ich gar nicht mal so sicher wäre, dass es bei einzelnen Werten überhaupt einen Unterschied macht. Habe schon einiges aufgeschnappt dazu, aber da ich keine stichhaltigen Links parat habe, lehne ich mich nicht weiter aus dem Fenster.
Gerade als Anfänger sollte man sich mit sowas nicht aufhalten. Kennen sollte man es, ja. Allein schon deshalb, weil es beim Umstieg auf andere Sprachen plötzlich relevant werden kann. Aber auch um auf unerwartete Überläufe reagieren zu können.
Gerade wegen letzterem, sollte man dann im Zweifel eher zum größeren Typ greifen. Für den alltäglichen Gebrauch ist int für Ganzzahlen und float für Kommazahlen aber völlig ausreichend.
Die mangelnde Präzision für Finanzanwendungen wurde ja auch schon angeschnitten. Da gibt es dann Klassen wie BigInteger und BigDecimal.
 
Zurück
Oben