4 Reaktionen

PHP Zufallszahlen aus negativen Zahlen oder Kommazahlen

Geschätzte Lesedauer:

Um es direkt vorweg zu sagen: die Nutzung von mt_rand() oder wenn nötig auch rand() ist auf jeden Fall schneller. Allerdings ist es bei mir schon häufiger vorgekommen, dass ich Zufallszahlen benötigt habe, die keine ganzen Zahlen oder nicht positiv waren.

Für die Nutzung von negativen Zahlen ist die einfachste Variante einen Wert zu addieren und später wieder abzuziehen:

[pastacode lang=“php“ message=“PHP“ highlight=““ provider=“manual“]

$a = -100;
$b = -20;
 
$a += 100;
$b += 100;
 
$num = mt_rand($a, $b);
$num -= 100;

[/pastacode]

Das funktioniert natürlich auch, wenn man nicht weiß, welchen Wert $a hat, indem man einfach $a zwischenspeichert und diesen Wert abzieht (er ist ja negativ) und später wieder addiert.

[pastacode lang=“php“ message=“PHP“ highlight=““ provider=“manual“]

$a = -100;
$b = -20;
 
$sub = $a;
$a -= $sub;
$b -= $sub;
 
$num = mt_rand($a, $b);
$num += $sub;

[/pastacode]

Bei Kommazahlen ist das Ganze schon schwieriger. Die einfachste Variante hierbei ist eine maximale Anzahl an Kommastellen festzulegen (ich nehme hierbei 5).

[pastacode lang=“php“ message=“PHP“ highlight=““ provider=“manual“]

$a = 0.234534;
$b = 12.7;
 
$multi = pow(10, 5); // Anzahl Kommastellen
 
$num = mt_rand(round($a * $multi), round($b * $multi)) / $multi;

[/pastacode]

Zuerst wird der Multiplikator festgelegt, in diesem Fall für 5 Kommastellen, so dass aus 0.234534 danach 23453.4 wird und aus 12.7 wird 1270000. Aus diesem Bereich wird nun eine Zufallszahl gezogen. Dabei wird die 6. Kommastelle der ersten Zahl vorher abgeschnitten bzw. weggerundet. Die entstandene Zufallszahl (z. B. 10443) wird nun wieder dividiert und man hat das gewünschte Ergebnis 0.10443

Es gibt auch die Möglichkeit die Anzahl der Kommastellen automatisch zu berechnen, ich würde davon aber abraten, da es sehr langsam ist. Hierbei wird der Multiplikator nicht wie vorher festgelegt, sondern ausgerechnet:

[pastacode lang=“php“ message=“PHP“ highlight=““ provider=“manual“]

$multi = 1;
if(intval($a) != $a) {
    $tmp = $a - intval($a);
    $tmp = pow(10, strlen($tmp) - 2);
    if($tmp > $multi) $multi = $tmp;
}
if(intval($b) != $b) {
    $tmp = $b - intval($b);
    $tmp = pow(10, strlen($tmp) - 2);
    if($tmp > $multi) $multi = $tmp;
}

[/pastacode]

Ich habe wie gesagt diese Methode nicht verwendet, da sie etwa doppelt so lange benötigt wie ein fester Multiplikator.
Hier nun noch meine komplette get_random Funktion:

[pastacode lang=“php“ message=“PHP“ highlight=““ provider=“manual“]

function get_random($min, $max, $round_to = 5) {
     
    if($min > $max) {
        $tmp = $min;
        $min = $max;
        $max = $tmp;
    }
     
    $sub = 0;
     
    if($min < 0) {
        $sub = $min;
        $min -= $sub;
        $max -= $sub;
    }
    
    if(intval($min) != $min || intval($max) != $max) {
        $multi = pow(10, $round_to);
        $num = mt_rand(round($min * $multi), round($max * $multi)) / $multi;
    } else {
        $num = mt_rand($min, $max);
    }
     
    $num += $sub;
     
    return $num;
}

[/pastacode]

Diese Funktion funktioniert mit negativen Zahlen, Kommazahlen und auch mit vertauschten Werten. Ich würde aber dringend dazu raten sie nur zu verwenden, wenn es notwendig ist und bei normalen positiven ganzen Zahlen immer mt_rand zu nutzen.
Beachtet auch unbedingt, dass die Angabe des Parameters $round_to entscheidet, in welchen Schritten die Zufallszahlen liegen. get_random(0.1, 0.5, 5) gibt also auch 0.23643 zurück. Wenn ihr dabei wirklich nur 0.1er Schritte möchtet müsst ihr auch get_random(0.1, 0.5, 1) verwenden.

Dieser Artikel wurde von Marius Burkard verfasst.

Marius Burkard ist Diplom-Wirtschaftsinformatiker und arbeitet seit 2006 als selbstständiger Software-Entwickler und Linux-Server-Administrator mit der Firma pixcept KG. Er ist unter anderem mitverantwortlich für die Projekte Was-lese-ich.de und ISPProtect.

4 Kommentare - bis jetzt!

Eigenen Kommentar verfassen
  1. Bachsau
    schrieb am :

    Kommazahlen: Nimm eine beliebige Primzahl, und teil sie durch einen per mt_rand() ermittelten wert.
    Negative Zahlen: Ermittle einen Wert mit mt_rand() und multipliziere ihn mit -1.

    Wo ist das Problem?

  2. schrieb am :

    Das ist nicht ganz korrekt.
    Mit der Methode würde es keine Zufallszahl zwischen -10 und 10 zum Beispiel geben.
    Bei der Verwendung von Teilern gibt es das Problem, dass die Zufallszahlen nicht gleichmäßig verteilt sind.

  3. MC Hammer
    schrieb am :

    Mit negativen Zahlen scheint das Skript Probleme zu haben habe einen bereich von -0.3 bis 0.3 angegeben und bekomme dann als Ergebnisse die sogar größer als 0.3 sind, dass kann ja nicht wirklich stimmen.

  4. schrieb am :

    Hallo und Danke für den Hinweis…

    Komisch, dass das noch niemandem aufgefallen ist, natürlich muss es in der vorletzten Codezeile heißen += und nicht -=

    Habe ich nun korrigiert.

Und jetzt du! Deine Meinung?

Erforderliche Felder sind mit einem Asterisk (*) gekennzeichnet. Die E-Mail-Adresse wird nicht veröffentlicht.
  1. Nach Absenden des Kommentar-Formulars erfolgt eine Verarbeitung der von Ihnen eingegebenen personenbezogenen Daten durch den datenschutzrechtlich Verantwortlichen zum Zweck der Bearbeitung Ihrer Anfrage auf Grundlage Ihrer durch das Absenden des Formulars erteilten Einwilligung.
    Weitere Informationen