java joptionpane - Warum gibt das Teilen eines Floats durch eine Ganzzahl 0.0 zurück?





beispiel showoptiondialog (6)


Andere haben bereits gute Antworten gegeben. Wenn Sie möchten, dass Ihre Skala eine ganze Zahl ist (was sinnvoll ist, wenn Ihr n bereits eine ganze Zahl ist), könnten Sie das tun

int scale = ((255 * n)/1024);

Beachten Sie, dass Sie damit keine Probleme bekommen, solange dies die Zahlen sind, da n * 255 immer in ein int passt, wenn das Maximum n = 1024 ist.

flexibler wäre

int scale(int value, int old_max, int new_max){
  java.math.BigInteger big_value = java.math.BigInteger.valueOf(value);
  java.math.BigInteger big_old_max = java.math.BigInteger.valueOf(old_max);
  java.math.BigInteger big_new_max = java.math.BigInteger.valueOf(new_max);
  java.math.BigInteger mult = big_value.multiply(big_old_max);
  return (int) mult.devide(big_new_max).doubleValue();
}

Sie werden auf diese Weise keine Ints überlaufen, obwohl ich zugeben muss, dass dies ein bisschen ausführlich ist

Bearbeiten:

Grundsätzlich gleich, aber weniger klobig (obwohl bei sehr hohen Zahlen einige Präzessionsfehler auftreten können)

int scale(int value, int old_max, int new_max){
  double factor = (double) new_max / (double) old_max;
  return factor * value;
}

Also, wenn ich einen Bereich von Zahlen '0 - 1024' habe und ich möchte sie in '0 - 255' bringen, würde die Mathematik diktieren, die Eingabe durch das Maximum zu dividieren, das der Eingang sein wird (1024 in diesem Fall), was geben wird mir eine Nummer zwischen 0.0 - 1.0. dann multipliziere das mit dem Zielbereich (255).

Was ich machen möchte!

Aber aus irgendeinem Grund in Java (mit der Verarbeitung) wird immer der Wert 0 zurückgegeben.

Der Code wäre so einfach

float scale;
scale = (n/1024) * 255;

Aber ich bekomme nur 0.0. Ich habe es doppelt und int versucht. alles vergebens. WARUM!?




In Ihrem Fall ergibt n/1024 0, da Sie eine Ganzzahldivision durchführen. Um dies zu überwinden, kannst du n float . Dadurch erhalten Sie ein Ergebnis zwischen 0.0 und 1.0 , multiplizieren Sie mit 255 und werfen Sie das Ergebnis wieder auf Integer zurück. Außerdem müssen Sie scale als int deklarieren

int scale;
int n = 80; 
scale = (int)(((float)n/1024) * 255);



n / 1024 ist eine Ganzzahldivision , die eine ganze Zahl ergibt (dh in diesem Fall 0).

Verwenden n / 1024.0 stattdessen n / 1024.0 .




Das liegt daran, dass Sie Integer-Division machen.

Teile durch ein Double oder Float, und es wird funktionieren:

double scale = ( n / 1024.0 ) * 255 ;

Oder, wenn Sie es als Schwimmer wollen,

float scale = ( n / 1024.0f ) * 255 ;



Ich nehme an, dass n ein int . Da die Konstanten 1024 und 255 beide int alle Berechnungen auf der rechten Seite mit Ganzzahlarithmetik durchgeführt. Das bedeutet, dass das Ergebnis von n/1024 auf einen ganzzahligen Wert n/1024 wird, bevor es mit 255 multipliziert wird.

Jede dieser Änderungen wird die Berechnungen richtig funktionieren lassen:

scale = n / 1024.0 * 255.0;       // Use double constants.
scale = (double) n / 1024 * 255;  // Convert n to a double.
scale = n * 255 / 1024;           // Multiply before dividing.

Die letzte Methode verwendet Integer-Mathematik, aber die Reihenfolge der Operationen zu ändern bedeutet, dass Sie die unerwünschte Trunkierung nicht auf 0 setzen. Sie erhalten trotzdem nur Integer-Antworten, so dass Sie alle Dezimalpunkte in den Antworten verlieren.




Zusammenfassung

In Java 6 (und vermutlich früher) wird round(x) als floor(x+0.5) implementiert. 1 Dies ist ein Spezifikationsfehler, genau für diesen einen pathologischen Fall. 2 Java 7 macht diese fehlerhafte Implementierung nicht länger erforderlich. 3

Das Problem

0.5 + 0.49999999999999994 ist genau 1 in doppelter Genauigkeit:

static void print(double d) {
    System.out.printf("%016x\n", Double.doubleToLongBits(d));
}

public static void main(String args[]) {
    double a = 0.5;
    double b = 0.49999999999999994;

    print(a);      // 3fe0000000000000
    print(b);      // 3fdfffffffffffff
    print(a+b);    // 3ff0000000000000
    print(1.0);    // 3ff0000000000000
}

Dies liegt daran, dass 0,49999999999999994 einen kleineren Exponenten als 0,5 hat. Wenn sie addiert werden, wird ihre Mantisse verschoben und die ULP wird größer.

Die Lösung

Seit Java 7 implementiert OpenJDK (zum Beispiel) es so: 4

public static long round(double a) {
    if (a != 0x1.fffffffffffffp-2) // greatest double value less than 0.5
        return (long)floor(a + 0.5d);
    else
        return 0;
}

1. http://docs.oracle.com/javase/6/docs/api/java/lang/Math.html#round%28double%29

2. http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6430675 (Dank an @SimonNickerson, um das zu finden)

3. http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#round%28double%29

4. http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/lang/Math.java#Math.round%28double%29





java math division integer-division