Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > de.comp.lang.php > #4428 > unrolled thread

var_dump(8.7 <= 8.7) / false?

Started byStefan Mayer <meniskus@gmx.net>
First post2018-11-15 01:23 +0100
Last post2018-11-19 20:52 +0100
Articles 19 — 5 participants

Back to article view | Back to de.comp.lang.php


Contents

  var_dump(8.7 <= 8.7) / false? Stefan Mayer <meniskus@gmx.net> - 2018-11-15 01:23 +0100
    Re: var_dump(8.7 <= 8.7) / false? Arno Welzel <usenet@arnowelzel.de> - 2018-11-15 09:12 +0100
      Re: var_dump(8.7 <= 8.7) / false? Arno Welzel <usenet@arnowelzel.de> - 2018-11-15 09:15 +0100
        Re: var_dump(8.7 <= 8.7) / false? Stefan Mayer <meniskus@gmx.net> - 2018-11-15 14:31 +0100
          Re: var_dump(8.7 <= 8.7) / false? "Christoph M. Becker" <cmbecker69@arcor.de> - 2018-11-15 14:51 +0100
            Re: var_dump(8.7 <= 8.7) / false? Stefan Mayer <meniskus@gmx.net> - 2018-11-15 15:52 +0100
              Re: var_dump(8.7 <= 8.7) / false? "Christoph M. Becker" <cmbecker69@arcor.de> - 2018-11-15 17:36 +0100
                Re: var_dump(8.7 <= 8.7) / false? Stefan Mayer <meniskus@gmx.net> - 2018-11-15 18:02 +0100
                Re: var_dump(8.7 <= 8.7) / false? Stefan Mayer <meniskus@gmx.net> - 2018-11-15 21:24 +0100
                  Re: var_dump(8.7 <= 8.7) / false? "Christoph M. Becker" <cmbecker69@arcor.de> - 2018-11-16 14:43 +0100
                    Re: var_dump(8.7 <= 8.7) / false? Stefan Mayer <meniskus@gmx.net> - 2018-11-16 21:26 +0100
                      Re: var_dump(8.7 <= 8.7) / false? "Christoph M. Becker" <cmbecker69@arcor.de> - 2018-11-17 23:49 +0100
                        Re: var_dump(8.7 <= 8.7) / false? Stefan Mayer <meniskus@gmx.net> - 2018-11-19 21:15 +0100
          Re: var_dump(8.7 <= 8.7) / false? Claus Reibenstein <4spamersonly@kabelmail.de> - 2018-11-15 19:34 +0100
            Re: var_dump(8.7 <= 8.7) / false? Stefan Mayer <meniskus@gmx.net> - 2018-11-15 21:06 +0100
    Re: var_dump(8.7 <= 8.7) / false? Stefan Mayer <meniskus@gmx.net> - 2018-11-15 09:13 +0100
      Re: var_dump(8.7 <= 8.7) / false? "Christoph M. Becker" <cmbecker69@arcor.de> - 2018-11-15 12:22 +0100
    Re: var_dump(8.7 <= 8.7) / false? "Peter J. Holzer" <hjp-usenet3@hjp.at> - 2018-11-17 20:55 +0100
      Re: var_dump(8.7 <= 8.7) / false? Stefan Mayer <meniskus@gmx.net> - 2018-11-19 20:52 +0100

#4428 — var_dump(8.7 <= 8.7) / false?

FromStefan Mayer <meniskus@gmx.net>
Date2018-11-15 01:23 +0100
Subjectvar_dump(8.7 <= 8.7) / false?
Message-ID<61959674.20181115012304@gmx.net>
Hallo Leute,

eine kleine Funktion die Werte zwischen "min" und "max"

```
<?php
function f($min, $max, $step) {
    $values = [];
    for ($i = $min; $i<=$max; $i+=$step) {
        $values[] = $i;
    }
    return $values;
}
```

Eigentlich dachte ich das funktioniert, aber irgendwas funktioniert überhaupt
nicht.

Wieso unterscheidet sich das Ergebnis z.B. bei diesen beiden?

print_r(f(11.3, 11.7, .4)); // 11.7 fehlt
print_r(f(20.3, 20.7, .4)); // OK


z.B.

print_r(f(5.3, 5.7, .4)); // OK

 [0] => 5.3
 [1] => 5.7


print_r(f(8.3, 8.7, .4)); // 8.7 fehlt?

  [0] => 8.3

print_r(f(9.2, 11, .6));  // OK

 [0] => 9.2
 [1] => 9.8
 [2] => 10.4
 [3] => 11

print_r(f(11.3, 11.7, .4)); 11.7 fehlt?

 [0] => 11.3

print_r(f(20.3, 20.7, .4)); OK

 [0] => 20.3
 [1] => 20.7


Mehr händische Variante …

´´´
function f($min, $max, $step) {
    $values = [];
    $value = $min;
    while ($value <= $max) {
        $values[] = $value;
        $value+=$step;
    }
    return $values;
}
´´´

… gleiches Bild

Hilfe! Danke!

Gute Nacht, Stefan



[toc] | [next] | [standalone]


#4429

FromArno Welzel <usenet@arnowelzel.de>
Date2018-11-15 09:12 +0100
Message-ID<g54o42FdnvgU1@mid.individual.net>
In reply to#4428
Stefan Mayer:

> Hallo Leute,
> 
> eine kleine Funktion die Werte zwischen "min" und "max"
> 
> ```
> <?php
> function f($min, $max, $step) {
>     $values = [];
>     for ($i = $min; $i<=$max; $i+=$step) {
>         $values[] = $i;
>     }
>     return $values;
> }
> ```
> 
> Eigentlich dachte ich das funktioniert, aber irgendwas funktioniert überhaupt
> nicht.
> 
> Wieso unterscheidet sich das Ergebnis z.B. bei diesen beiden?
> 
> print_r(f(11.3, 11.7, .4)); // 11.7 fehlt
> print_r(f(20.3, 20.7, .4)); // OK


Fließkommazahlen für Vergleiche zu benutzen, ist generell problematisch.

Siehe auch:

<https://stackoverflow.com/questions/3148937/compare-floats-in-php>

Zitat:

"If you do it like this they should be the same. But note that a
characteristic of floating-point values is that calculations which seem
to result in the same value do not need to actually be identical. So if
$a is a literal .17 and $b arrives there through a calculation it can
well be that they are different, albeit both display the same value.

Usually you never compare floating-point values for equality like this,
you need to use a smallest acceptable difference:

if (abs(($a-$b)/$b) < 0.00001) {
  echo "same";
}

Something like that."


-- 
Arno Welzel
https://arnowelzel.de

[toc] | [prev] | [next] | [standalone]


#4431

FromArno Welzel <usenet@arnowelzel.de>
Date2018-11-15 09:15 +0100
Message-ID<g54o8cFdnvgU2@mid.individual.net>
In reply to#4429
Arno Welzel:

> Stefan Mayer:
> 
>> Hallo Leute,
>>
>> eine kleine Funktion die Werte zwischen "min" und "max"
>>
>> ```
>> <?php
>> function f($min, $max, $step) {
>>     $values = [];
>>     for ($i = $min; $i<=$max; $i+=$step) {
>>         $values[] = $i;
>>     }
>>     return $values;
>> }
>> ```
>>
>> Eigentlich dachte ich das funktioniert, aber irgendwas funktioniert überhaupt
>> nicht.
>>
>> Wieso unterscheidet sich das Ergebnis z.B. bei diesen beiden?
>>
>> print_r(f(11.3, 11.7, .4)); // 11.7 fehlt
>> print_r(f(20.3, 20.7, .4)); // OK
> 
> 
> Fließkommazahlen für Vergleiche zu benutzen, ist generell problematisch.
> 
> Siehe auch:
> 
> <https://stackoverflow.com/questions/3148937/compare-floats-in-php>
> 
> Zitat:
> 
> "If you do it like this they should be the same. But note that a
> characteristic of floating-point values is that calculations which seem
> to result in the same value do not need to actually be identical. So if
> $a is a literal .17 and $b arrives there through a calculation it can
> well be that they are different, albeit both display the same value.
> 
> Usually you never compare floating-point values for equality like this,
> you need to use a smallest acceptable difference:
> 
> if (abs(($a-$b)/$b) < 0.00001) {
>   echo "same";
> }
> 
> Something like that."

Ingrid weist mich noch darauf hin, dass das auch in der Dokumentation
von PHP erwähnt ist:

<http://php.net/manual/en/language.types.float.php>


-- 
Arno Welzel
https://arnowelzel.de

[toc] | [prev] | [next] | [standalone]


#4433

FromStefan Mayer <meniskus@gmx.net>
Date2018-11-15 14:31 +0100
Message-ID<06371490.20181115143113@gmx.net>
In reply to#4431
Arno Welzel am Donnerstag, 15. November 2018 (09:15):

> Arno Welzel:

>> Stefan Mayer:
>> 
>>> Hallo Leute,
>>>
>>> eine kleine Funktion die Werte zwischen "min" und "max"
>>>
>>> ```
>>> <?php
>>> function f($min, $max, $step) {
>>>     $values = [];
>>>     for ($i = $min; $i<=$max; $i+=$step) {
>>>         $values[] = $i;
>>>     }
>>>     return $values;
>>> }
>>> ```
>>>
>>> Eigentlich dachte ich das funktioniert, aber irgendwas funktioniert überhaupt
>>> nicht.
>>>
>>> Wieso unterscheidet sich das Ergebnis z.B. bei diesen beiden?
>>>
>>> print_r(f(11.3, 11.7, .4)); // 11.7 fehlt
>>> print_r(f(20.3, 20.7, .4)); // OK
>> 
>> 
>> Fließkommazahlen für Vergleiche zu benutzen, ist generell problematisch.
>> 
>> Siehe auch:
>> 
>> <https://stackoverflow.com/questions/3148937/compare-floats-in-php>
>> 
>> Zitat:
>> 
>> "If you do it like this they should be the same. But note that a
>> characteristic of floating-point values is that calculations which seem
>> to result in the same value do not need to actually be identical. So if
>> $a is a literal .17 and $b arrives there through a calculation it can
>> well be that they are different, albeit both display the same value.
>> 
>> Usually you never compare floating-point values for equality like this,
>> you need to use a smallest acceptable difference:
>> 
>> if (abs(($a-$b)/$b) < 0.00001) {
>>   echo "same";
>> }
>> 
>> Something like that."

> Ingrid weist mich noch darauf hin, dass das auch in der Dokumentation
> von PHP erwähnt ist:

> <http://php.net/manual/en/language.types.float.php>


Ja, Danke. Mittlerweile bin ich darauf auch gestoßen. Autsch.

Wie löse ich den nun den Vergleich der Werte? Durch das einbauen der "kleinen
Unterscheidung" in meine Funktion?

Das sähe so aus. Und funktioniert scheinbar.

```
function f($min, $max, $step)
{
    $values = [];
    $value = $min;
    while ($value <= $max || (abs(($value-$max)/$max) < 0.00001)) {
        $values[] = $value;
        $value+=$step;
    }
    return $values;
}
print_r(f(8.3, 8.7, .4));
print_r(f(10.3, 10.7, .4));
```

Gibt es daran etwas auszusetzen?  Alternative?

Danke und tschüss,
Stefan



[toc] | [prev] | [next] | [standalone]


#4434

From"Christoph M. Becker" <cmbecker69@arcor.de>
Date2018-11-15 14:51 +0100
Message-ID<psjtkk$rud$1@solani.org>
In reply to#4433
Am 15.11.2018 um 14:31 schrieb Stefan Mayer:

> Wie löse ich den nun den Vergleich der Werte? Durch das einbauen der "kleinen
> Unterscheidung" in meine Funktion?
> 
> Das sähe so aus. Und funktioniert scheinbar.
> 
> ```
> function f($min, $max, $step)
> {
>     $values = [];
>     $value = $min;
>     while ($value <= $max || (abs(($value-$max)/$max) < 0.00001)) {
>         $values[] = $value;
>         $value+=$step;
>     }
>     return $values;
> }
> print_r(f(8.3, 8.7, .4));
> print_r(f(10.3, 10.7, .4));
> ```
> 
> Gibt es daran etwas auszusetzen?

Siehe <https://floating-point-gui.de/errors/comparison/>.

> Alternative?

Wenn es wirklich genau sein muss, und die Performance sekundär ist,
würde ich das unter Umständen per BCMath[1] lösen. Kommt aber natürlich
darauf an, was du später mit diesen Werten tun willst.

[1] <http://php.net/manual/de/book.bc.php>

-- 
Christoph M. Becker

[toc] | [prev] | [next] | [standalone]


#4435

FromStefan Mayer <meniskus@gmx.net>
Date2018-11-15 15:52 +0100
Message-ID<4310540394.20181115155258@gmx.net>
In reply to#4434
Christoph M. Becker am Donnerstag, 15. November 2018 (14:51):

> Am 15.11.2018 um 14:31 schrieb Stefan Mayer:

>> Wie löse ich den nun den Vergleich der Werte? Durch das einbauen der "kleinen
>> Unterscheidung" in meine Funktion?
>> 
>> Das sähe so aus. Und funktioniert scheinbar.
>> 
>> ```
>> function f($min, $max, $step)
>> {
>>     $values = [];
>>     $value = $min;
>>     while ($value <= $max || (abs(($value-$max)/$max) < 0.00001)) {
>>         $values[] = $value;
>>         $value+=$step;
>>     }
>>     return $values;
>> }
>> print_r(f(8.3, 8.7, .4));
>> print_r(f(10.3, 10.7, .4));
>> ```
>> 
>> Gibt es daran etwas auszusetzen?

> Siehe <https://floating-point-gui.de/errors/comparison/>.

Cool, Danke. Das ist ja ein riesiges Thema.

"if( Math.abs(a-b) < 0.00001) // wrong - don't do this"
"if( Math.abs((a-b)/b) < 0.00001 ) // still not right!"

:-)


>> Alternative?

> Wenn es wirklich genau sein muss, und die Performance sekundär ist,
> würde ich das unter Umständen per BCMath[1] lösen.

> [1] <http://php.net/manual/de/book.bc.php>

Wow. Dessen war ich mir nicht bewußt. Das erscheint mir alles zu fett für meine
Fall. Aber auf alle Fälle hab ich was zu lesen.


> kommt aber natürlich darauf an, was du später mit diesen Werten tun willst.

Aus den Werten werden Daten für "select" Elemente im Frontend erzeugt. Der
Anspruch ist, alle Werte des Bereichs zu erstellen. Es geht nicht hauptsächlich
um die Zahlen selbst.

Neuer Versuch:

Die Funktion hat einen weiteren Schalter "zero". Der Wert "0" soll bei "false"
auslassen werden. Nun birgt ja ein Vergleich wie "0 ==(=) $value" genau das
gleiche Problem wieder.

Sehe ich das richtig, das Vergleiche $a>$b oder $a<$b zulässig sind?

Wenn ja, wäre es dann eine Lösung die Stellen, welche auf Gleichheit prüfen, in
Zeichenketten zu wandeln?

"(string)0.00" $value wird zu "0"
"(string)2.50"  $max"  wird zu "2.5"

Da kommt ja was sicheres zum Vergleichen raus, oder?

Beispiel:

Wieder funktioniert es scheinbar.

```php
function buildRange($min, $max, $step, $zero = true)
{
    $values = [];
    $value = $min;
    while ($value < $max || (string)$value === (string)$max) {
        if (false === $zero && '0' === (string)$value) {
            $value += $step;
            continue;
        }
        $values[] = $value;
        $value += $step;
    }
    return $values;
}
print_r(buildRange(-1, 1, .5, false));
print_r(buildRange(-1, 1, .5, true));
print_r(buildRange(5.3, 5.7, .4));
```

Ist das OK? Neue Probleme?


ciao, Stefan

[toc] | [prev] | [next] | [standalone]


#4436

From"Christoph M. Becker" <cmbecker69@arcor.de>
Date2018-11-15 17:36 +0100
Message-ID<psk79f$36s$1@solani.org>
In reply to#4435
Am 15.11.2018 um 15:52 schrieb Stefan Mayer:

> Christoph M. Becker am Donnerstag, 15. November 2018 (14:51):
> 
>> kommt aber natürlich darauf an, was du später mit diesen Werten tun willst.
> 
> Aus den Werten werden Daten für "select" Elemente im Frontend erzeugt. Der
> Anspruch ist, alle Werte des Bereichs zu erstellen. Es geht nicht hauptsächlich
> um die Zahlen selbst.

Okay, dann wäre BCMath schon mal gar nicht verkehrt.

> Neuer Versuch:
> 
> Die Funktion hat einen weiteren Schalter "zero". Der Wert "0" soll bei "false"
> auslassen werden. Nun birgt ja ein Vergleich wie "0 ==(=) $value" genau das
> gleiche Problem wieder.
> 
> Sehe ich das richtig, das Vergleiche $a>$b oder $a<$b zulässig sind?

Nein, die haben das gleiche Problem.

> Wenn ja, wäre es dann eine Lösung die Stellen, welche auf Gleichheit prüfen, in
> Zeichenketten zu wandeln?
> 
> "(string)0.00" $value wird zu "0"
> "(string)2.50"  $max"  wird zu "2.5"
> 
> Da kommt ja was sicheres zum Vergleichen raus, oder?

Probier mal

  (string) 9 < (string) 10

-- 
Christoph M. Becker

[toc] | [prev] | [next] | [standalone]


#4437

FromStefan Mayer <meniskus@gmx.net>
Date2018-11-15 18:02 +0100
Message-ID<34929869.20181115180235@gmx.net>
In reply to#4436
Christoph M. Becker am Donnerstag, 15. November 2018 (17:36):

> Am 15.11.2018 um 15:52 schrieb Stefan Mayer:

>> Christoph M. Becker am Donnerstag, 15. November 2018 (14:51):
>> 
>>> kommt aber natürlich darauf an, was du später mit diesen Werten tun willst.
>> 
>> Aus den Werten werden Daten für "select" Elemente im Frontend erzeugt. Der
>> Anspruch ist, alle Werte des Bereichs zu erstellen. Es geht nicht hauptsächlich
>> um die Zahlen selbst.

> Okay, dann wäre BCMath schon mal gar nicht verkehrt.

Ok. Ich versuche es.

>> Neuer Versuch:
>> 
>> Die Funktion hat einen weiteren Schalter "zero". Der Wert "0" soll bei "false"
>> auslassen werden. Nun birgt ja ein Vergleich wie "0 ==(=) $value" genau das
>> gleiche Problem wieder.
>> 
>> Sehe ich das richtig, das Vergleiche $a>$b oder $a<$b zulässig sind?

> Nein, die haben das gleiche Problem.

OK.

>> Wenn ja, wäre es dann eine Lösung die Stellen, welche auf Gleichheit prüfen, in
>> Zeichenketten zu wandeln?
>> 
>> "(string)0.00" $value wird zu "0"
>> "(string)2.50"  $max"  wird zu "2.5"
>> 
>> Da kommt ja was sicheres zum Vergleichen raus, oder?

> Probier mal

>   (string) 9 < (string) 10

Das geht natürlich nicht. Ich meinte nur die Stellen bei denen der variable Wert
auf Gleichheit mit '0' oder (string)$maxwert, verglichen werden soll.

$max = '8.00';

(string) 7.2   === '0' / false
(string) 0.00  === '0' / true
(string) 0     === '0' / true
(string) 8.25  === (string)$maxwert / false
(string) 8.00  === (string)$maxwert / true

Egal, ist jetzt eh hinfällig.

ciao, Stefan











[toc] | [prev] | [next] | [standalone]


#4440

FromStefan Mayer <meniskus@gmx.net>
Date2018-11-15 21:24 +0100
Message-ID<1652878720.20181115212444@gmx.net>
In reply to#4436
Christoph M. Becker am Donnerstag, 15. November 2018 (17:36):

> Am 15.11.2018 um 15:52 schrieb Stefan Mayer:

>> Christoph M. Becker am Donnerstag, 15. November 2018 (14:51):
>> 
>>> kommt aber natürlich darauf an, was du später mit diesen Werten tun willst.
>> 
>> Aus den Werten werden Daten für "select" Elemente im Frontend erzeugt. Der
>> Anspruch ist, alle Werte des Bereichs zu erstellen. Es geht nicht hauptsächlich
>> um die Zahlen selbst.

> Okay, dann wäre BCMath schon mal gar nicht verkehrt.

>> Neuer Versuch:
>> 
>> Die Funktion hat einen weiteren Schalter "zero". Der Wert "0" soll bei "false"
>> auslassen werden. Nun birgt ja ein Vergleich wie "0 ==(=) $value" genau das
>> gleiche Problem wieder.
>> 
>> Sehe ich das richtig, das Vergleiche $a>$b oder $a<$b zulässig sind?

> Nein, die haben das gleiche Problem.

>> Wenn ja, wäre es dann eine Lösung die Stellen, welche auf Gleichheit prüfen, in
>> Zeichenketten zu wandeln?
>> 
>> "(string)0.00" $value wird zu "0"
>> "(string)2.50"  $max"  wird zu "2.5"
>> 
>> Da kommt ja was sicheres zum Vergleichen raus, oder?

> Probier mal

>   (string) 9 < (string) 10


Neuer Versuch mit bccomp. Wieder funktioniert es scheinbar.

```
function buildRange($min, $max, $step, $zero = true)
{
    $values = [];
    $value = $min;

    /**
     * https://secure.php.net/manual/de/function.bccomp.php
     *  0 wenn beide Operatoren gleich sind
     *  1 wenn left_operand größer ist als right_operand,
     *  -1 sonst
     */
    while (1 !== bccomp((string)$value, (string)$max, 2)) {
        if (false === $zero && 0 === bccomp((string)$value, '0',2)) {
            $value += $step;
            continue;
        }
        $values[] = $value;
        $value+=$step;
    }
    return $values;
}
print_r(buildRange(8.3, 8.7, .4));
print_r(buildRange(7.9, 8.7, .4));
print_r(buildRange(-1.25, 2.75, .5, false));
print_r(buildRange(-1, 1, .5, false));
print_r(buildRange(-1, 1, .5, true));
```

OK? Einwände? Probleme?

Danke und tschüss, Stefan











[toc] | [prev] | [next] | [standalone]


#4441

From"Christoph M. Becker" <cmbecker69@arcor.de>
Date2018-11-16 14:43 +0100
Message-ID<psmhid$k0q$1@solani.org>
In reply to#4440
Am 15.11.2018 um 21:24 schrieb Stefan Mayer:

> Neuer Versuch mit bccomp. Wieder funktioniert es scheinbar.
> 
> ```
> function buildRange($min, $max, $step, $zero = true)
> {
>     $values = [];
>     $value = $min;
> 
>     /**
>      * https://secure.php.net/manual/de/function.bccomp.php
>      *  0 wenn beide Operatoren gleich sind
>      *  1 wenn left_operand größer ist als right_operand,
>      *  -1 sonst
>      */
>     while (1 !== bccomp((string)$value, (string)$max, 2)) {
>         if (false === $zero && 0 === bccomp((string)$value, '0',2)) {
>             $value += $step;
>             continue;
>         }
>         $values[] = $value;
>         $value+=$step;
>     }
>     return $values;
> }
> print_r(buildRange(8.3, 8.7, .4));
> print_r(buildRange(7.9, 8.7, .4));
> print_r(buildRange(-1.25, 2.75, .5, false));
> print_r(buildRange(-1, 1, .5, false));
> print_r(buildRange(-1, 1, .5, true));
> ```
> 
> OK? Einwände? Probleme?

Sollte so funktionieren. Ein paar Anregungen:

* Man könnte bccomp() als typische Vergleichsfunktion verwenden, die <
0, == 0 oder > 0 zurückliefert. Also statt 1 !== eben 0 >= schreiben.

* Man könnte buildRange() gleich Strings übergeben, um jedwedes Problem
mit Fließkommazahlen zum umschiffen. Das ist außerdem etwas effizienter.

* Man könnte hier auf die (string) Casts verzichten. Die Wandlung nimmt
PHP ohnehin automatisch vor.

* Man könnte automatisierte Tests schreiben. Sollte sich doch ein Fehler
in der Funktion finden, dann kann man diesen korrigieren, und die Tests
zeigen dann, ob alles was vorher funktioniert hat noch immer
funktioniert. Und natürlich für den Fehler gleich einen passenden Test
ergänzen.

-- 
Christoph M. Becker

[toc] | [prev] | [next] | [standalone]


#4442

FromStefan Mayer <meniskus@gmx.net>
Date2018-11-16 21:26 +0100
Message-ID<958057513.20181116212645@gmx.net>
In reply to#4441
Christoph M. Becker am Freitag, 16. November 2018 (14:43):

> Am 15.11.2018 um 21:24 schrieb Stefan Mayer:

>> Neuer Versuch mit bccomp. Wieder funktioniert es scheinbar.
>> 
>> ```
>> function buildRange($min, $max, $step, $zero = true)
>> {
>>     $values = [];
>>     $value = $min;
>> 
>>     /**
>>      * https://secure.php.net/manual/de/function.bccomp.php
>>      *  0 wenn beide Operatoren gleich sind
>>      *  1 wenn left_operand größer ist als right_operand,
>>      *  -1 sonst
>>      */
>>     while (1 !== bccomp((string)$value, (string)$max, 2)) {
>>         if (false === $zero && 0 === bccomp((string)$value, '0',2)) {
>>             $value += $step;
>>             continue;
>>         }
>>         $values[] = $value;
>>         $value+=$step;
>>     }
>>     return $values;
>> }
>> ```
>> 
>> OK? Einwände? Probleme?

> Sollte so funktionieren. Ein paar Anregungen:

> * Man könnte bccomp() als typische Vergleichsfunktion verwenden, die <
0, == 0 oder >> 0 zurückliefert. Also statt 1 !== eben 0 >= schreiben.

Liest sich definitiv natürlicher, ich hatte es so. Allerdings war
ausschlaggebend, dass ich definitiv wußte was ich nicht haben will, und das ist
halt '-1'. Ich hab's wieder nach Deinem Vorschlag geändert. Es ist einfach
verständlicher.


> * Man könnte buildRange() gleich Strings übergeben, um jedwedes Problem
> mit Fließkommazahlen zum umschiffen. Das ist außerdem etwas effizienter.

Diesen Vorschlag nehme ich gerne auf.


> * Man könnte hier auf die (string) Casts verzichten. Die Wandlung nimmt
> PHP ohnehin automatisch vor.

Wenn ich das im PHP-Quelltext selbst verifizieren möchte, wo muss ich da
schauen? Wo finde ich den auf github.com/php die entsprechende Stelle?

Nächster Einschlag:

Rauskommen sollen Gleitkommazahlen, damit man die z.B. number_format behandeln
kann.

```
function buildRange(string $min, string $max, string $step, $zero = true): array
{
    $values = [];
    $value = $min;
    while (0 >= bccomp($value, $max, 2)) {
        if (false === $zero && 0 === bccomp($value, '0', 2)) {
            $value = bcadd($value, $step, 2);
            continue;
        }
        $values[] = (float)$value;
        $value = bcadd($value, $step, 2);
    }
    return $values;
}
print_r(buildRange(8.3, 8.7, .4));
var_dump(buildRange(-2.3, 1.7, .6, false));
```

Geht das in Ordnung?


> * Man könnte automatisierte Tests schreiben. Sollte sich doch ein Fehler
> in der Funktion finden, dann kann man diesen korrigieren, und die Tests
> zeigen dann, ob alles was vorher funktioniert hat noch immer
> funktioniert. Und natürlich für den Fehler gleich einen passenden Test
> ergänzen.

Das hört sich gut an. Weiß aber grad nicht wie genau.


Vielen Dank für die sehr aufschlussreiche Hilfe und schönen Abend noch.

adios, Stefan



[toc] | [prev] | [next] | [standalone]


#4444

From"Christoph M. Becker" <cmbecker69@arcor.de>
Date2018-11-17 23:49 +0100
Message-ID<psq5t8$4an$1@solani.org>
In reply to#4442
Am 16.11.2018 um 21:26 schrieb Stefan Mayer:

> Christoph M. Becker am Freitag, 16. November 2018 (14:43):
> 
>> * Man könnte hier auf die (string) Casts verzichten. Die Wandlung nimmt
>> PHP ohnehin automatisch vor.
> 
> Wenn ich das im PHP-Quelltext selbst verifizieren möchte, wo muss ich da
> schauen? Wo finde ich den auf github.com/php die entsprechende Stelle?

Ausgehend vom Parameter-Parsing von bccomp()[1], kommt man über
zend_parse_arg_str()[2] zu zend_parse_arg_str_weak()[3] wo alles was
sich irgendwie in eine Zeichenkette konvertieren lässt, eben umgewandelt
wird (und alles andere einen Fehler ergibt).

> Nächster Einschlag:
> 
> Rauskommen sollen Gleitkommazahlen, damit man die z.B. number_format behandeln
> kann.

Hm, wenn du zwischenzeitlich doch Gleitkommazahlen haben möchtest, dann
erscheint mir die BCMath-Lösung fraglich, und du fährst mit der Addition
des halben Intervalls wie von Claus vorgeschlagen[4], oder der
Integer-Schleife wie von Peter vorgeschlagen[5], vermutlich besser. Ich
frage mich allerdings, ob du number_format() wirklich brauchst. Ein
wenig Zeichenkettenmanipulation könnte es auch tun (z.B. wenn du nur den
Dezimalpunkt in ein -komma ändern willst).

>> * Man könnte automatisierte Tests schreiben. Sollte sich doch ein Fehler
>> in der Funktion finden, dann kann man diesen korrigieren, und die Tests
>> zeigen dann, ob alles was vorher funktioniert hat noch immer
>> funktioniert. Und natürlich für den Fehler gleich einen passenden Test
>> ergänzen.
> 
> Das hört sich gut an. Weiß aber grad nicht wie genau.

Siehe z.B. <https://phpunit.de/>.

Noch der Vollständigkeit halber erwähnen möchte ich die range() Funktion
von PHP, die eigentlich so ziemlich genau das macht wie dein erster
Ansatz, und auch das gleiche Problem bezüglich Gleitkommazahlen hat.
Immerhin meldet diese aber zumindest in aktuellen PHP-Versionen einen
Fehler, wenn es zu solchen Gleitkommaproblemen kommt ("step exceeds the
specified range").

[1]
<https://github.com/php/php-src/blob/php-7.3.0RC5/ext/bcmath/bcmath.c#L517-L518>
[2] <https://github.com/php/php-src/blob/php-7.3.0RC5/Zend/zend_API.h#L1187>
[3] <https://github.com/php/php-src/blob/php-7.3.0RC5/Zend/zend_API.c#L514>
[4] <news:g55shjFliudU1@mid.individual.net>
[5] <news:slrnpv0sho.s8s.hjp-usenet3@hrunkner.hjp.at>

-- 
Christoph M. Becker

[toc] | [prev] | [next] | [standalone]


#4446

FromStefan Mayer <meniskus@gmx.net>
Date2018-11-19 21:15 +0100
Message-ID<1606187959.20181119211513@gmx.net>
In reply to#4444
Christoph M. Becker am Samstag, 17. November 2018 (23:49):

> Am 16.11.2018 um 21:26 schrieb Stefan Mayer:

>> Rauskommen sollen Gleitkommazahlen, damit man die z.B. number_format
>> behandeln kann.

> Hm, wenn du zwischenzeitlich doch Gleitkommazahlen haben möchtest, dann
> erscheint mir die BCMath-Lösung fraglich, und du fährst mit der Addition des
> halben Intervalls wie von Claus vorgeschlagen[4], oder der Integer-Schleife
> wie von Peter vorgeschlagen[5], vermutlich besser. Ich frage mich allerdings,
> ob du number_format() wirklich brauchst. Ein wenig Zeichenkettenmanipulation
> könnte es auch tun (z.B. wenn du nur den Dezimalpunkt in ein -komma ändern
> willst).

Du hast recht. Ich bin nicht wirklich an der Zahl interessiert, sondern
tatsächlich an der Zeichenkette "1,75" oder "0,50", deshalb lasse ich es mit
BCMath. Zeichenkette rein, Zeichenkette raus. Ich denke das passt.

Herzlichen Dank für die Hilfestellung/Tipps. Bis demnächst :-)

Schönen Abend noch.
tschüss, Stefan


[toc] | [prev] | [next] | [standalone]


#4438

FromClaus Reibenstein <4spamersonly@kabelmail.de>
Date2018-11-15 19:34 +0100
Message-ID<g55shjFliudU1@mid.individual.net>
In reply to#4433
Stefan Mayer schrieb am 15.11.2018 um 14:31:

>     while ($value <= $max || (abs(($value-$max)/$max) < 0.00001)) {

Versuch's mal hiermit:

    while ($value < $max + $step / 2) {

Gruß
Claus

[toc] | [prev] | [next] | [standalone]


#4439

FromStefan Mayer <meniskus@gmx.net>
Date2018-11-15 21:06 +0100
Message-ID<436878106.20181115210628@gmx.net>
In reply to#4438
Claus Reibenstein am Donnerstag, 15. November 2018 (19:34):

> Stefan Mayer schrieb am 15.11.2018 um 14:31:

>>     while ($value <= $max || (abs(($value-$max)/$max) < 0.00001)) {

> Versuch's mal hiermit:

>     while ($value < $max + $step / 2) {

Nee, Christoph hat mich überzeugt. Es muss was mit BCMath sein :-).

Danke, ciao.



[toc] | [prev] | [next] | [standalone]


#4430

FromStefan Mayer <meniskus@gmx.net>
Date2018-11-15 09:13 +0100
Message-ID<1727772643.20181115091327@gmx.net>
In reply to#4428
Stefan Mayer am Donnerstag, 15. November 2018 (01:23):

> ```
> <?php
> function f($min, $max, $step) {
>     $values = [];
>     for ($i = $min; $i<=$max; $i+=$step) {
>         $values[] = $i;
>     }
>     return $values;
> }
> ```

> Wieso unterscheidet sich das Ergebnis z.B. bei diesen beiden?

> print_r(f(11.3, 11.7, .4)); // 11.7 fehlt
> print_r(f(20.3, 20.7, .4)); // OK

Wie interpretiere ich den diese Angaben bei 3v4l.org?
https://3v4l.org/Odopi/vld#output

Danke.

ciao, Stefan










[toc] | [prev] | [next] | [standalone]


#4432

From"Christoph M. Becker" <cmbecker69@arcor.de>
Date2018-11-15 12:22 +0100
Message-ID<psjkst$lsl$1@solani.org>
In reply to#4430
Am 15.11.2018 um 09:13 schrieb Stefan Mayer:

> Wie interpretiere ich den diese Angaben bei 3v4l.org?
> https://3v4l.org/Odopi/vld#output

Soweit ich weiß, gibt es (noch) keine umfassende Dokumentation zu den
PHP 7 Opcodes. Etwas grundlegende Info findet man aber z.B. unter
<https://nikic.github.io/2017/04/14/PHP-7-Virtual-machine.html>.

Jedenfalls sind die Opcodes in diesem Fall irrelevant. Relevant ist der
Warnhinweis unter <http://php.net/manual/de/language.types.float.php>.

-- 
Christoph M. Becker

[toc] | [prev] | [next] | [standalone]


#4443

From"Peter J. Holzer" <hjp-usenet3@hjp.at>
Date2018-11-17 20:55 +0100
Message-ID<slrnpv0sho.s8s.hjp-usenet3@hrunkner.hjp.at>
In reply to#4428
On 2018-11-15 00:23, Stefan Mayer <meniskus@gmx.net> wrote:
> eine kleine Funktion die Werte zwischen "min" und "max"
>
> ```
><?php
> function f($min, $max, $step) {
>     $values = [];
>     for ($i = $min; $i<=$max; $i+=$step) {
>         $values[] = $i;
>     }
>     return $values;
> }
> ```
>
> Eigentlich dachte ich das funktioniert, aber irgendwas funktioniert überhaupt
> nicht.
>
> Wieso unterscheidet sich das Ergebnis z.B. bei diesen beiden?
>
> print_r(f(11.3, 11.7, .4)); // 11.7 fehlt
> print_r(f(20.3, 20.7, .4)); // OK

Die Annahme, dass Du mit den Werten 113/10, 117/10 und 4/10 rechnest,
wenn Du 11.3, 11.7 und .4 schreibst, ist falsch. 

Tatsächlich rechnest Du mit den Werten 3180667236830413/281474976710656,
3602879701896397/9007199254740992 und 3293257227514675/281474976710656
(die Brüche sehen im Dezimalsystem sehr "unrund" aus, aber die Nenner
sind schöne runde Zahlen im Binärsystem).

3180667236830413/281474976710656 + 3602879701896397/9007199254740992 ist
(auf ganze 281474976710656stel gerundet)
3293257227514676/281474976710656, also größer als
3293257227514675/281474976710656. Somit liefert <= false.

BCD-Arithmetik wurde schon als Lösung genannt, ebenfalls ein halbes
Intervall draufschlagen.

Wenn Du weißt, dass 1/10 Deine Einheit ist (häufig bei finanziellen
Berechnungen, wo oft 1/100 die Einheit ist), dann rechne einfach mit
ganzen Werten:

    for ($i = 113; $i <= 117; $i += 4) {
        $values[] = $i / 10;
    }

Wenn Du Floatingpoint-Werte übergeben musst, dann musst Du die Werte
mit round runden, um ganze Zehntel zu erhalten:

    for ($i = round($min * 10) $i <= round($max * 10); $i += round($step * 10)) {
        ... $i / 10 ...
    }

Aber wie gesagt, das ist nur dann sinnvoll, wenn das, womit Du da
rechnest, abzählbar ist (wie z.B. Geldbeträge). Wenn Das kontinuierlich
ist (Länge, Zeit, ...), dann ist FP-Arithmetik genau das richtige und Du
solltest nicht versuchen, die Ergebnisse durch Runden "schöner" zu
machen: Du bringst dadurch nur zusätzliche Fehler rein.

        hp


-- 
   _  | Peter J. Holzer    | Fluch der elektronischen Textverarbeitung:
|_|_) |                    | Man feilt solange an seinen Text um, bis
| |   | hjp@hjp.at         | die Satzbestandteile des Satzes nicht mehr
__/   | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel

[toc] | [prev] | [next] | [standalone]


#4445

FromStefan Mayer <meniskus@gmx.net>
Date2018-11-19 20:52 +0100
Message-ID<1465382240.20181119205228@gmx.net>
In reply to#4443
Peter J. Holzer am Samstag, 17. November 2018 (20:55):

> On 2018-11-15 00:23, Stefan Mayer <meniskus@gmx.net> wrote:
>> eine kleine Funktion die Werte zwischen "min" und "max"
>>
>> ```
>><?php
>> function f($min, $max, $step) {
>>     $values = [];
>>     for ($i = $min; $i<=$max; $i+=$step) {
>>         $values[] = $i;
>>     }
>>     return $values;
>> }
>> ```
>>
>> Eigentlich dachte ich das funktioniert, aber irgendwas funktioniert überhaupt
>> nicht.
>>
>> Wieso unterscheidet sich das Ergebnis z.B. bei diesen beiden?
>>
>> print_r(f(11.3, 11.7, .4)); // 11.7 fehlt
>> print_r(f(20.3, 20.7, .4)); // OK

> Die Annahme, dass Du mit den Werten 113/10, 117/10 und 4/10 rechnest,
> wenn Du 11.3, 11.7 und .4 schreibst, ist falsch. 

> Tatsächlich rechnest Du mit den Werten 3180667236830413/281474976710656,
> 3602879701896397/9007199254740992 und 3293257227514675/281474976710656
> (die Brüche sehen im Dezimalsystem sehr "unrund" aus, aber die Nenner
> sind schöne runde Zahlen im Binärsystem).

> 3180667236830413/281474976710656 + 3602879701896397/9007199254740992 ist
> (auf ganze 281474976710656stel gerundet)
> 3293257227514676/281474976710656, also größer als
> 3293257227514675/281474976710656. Somit liefert <= false.

> BCD-Arithmetik wurde schon als Lösung genannt, ebenfalls ein halbes
> Intervall draufschlagen.

> Wenn Du weißt, dass 1/10 Deine Einheit ist (häufig bei finanziellen
> Berechnungen, wo oft 1/100 die Einheit ist), dann rechne einfach mit
> ganzen Werten:

>     for ($i = 113; $i <= 117; $i += 4) {
>         $values[] = $i / 10;
>     }

> Wenn Du Floatingpoint-Werte übergeben musst, dann musst Du die Werte
> mit round runden, um ganze Zehntel zu erhalten:

>     for ($i = round($min * 10) $i <= round($max * 10); $i += round($step * 10)) {
>         ... $i / 10 ...
>     }

> Aber wie gesagt, das ist nur dann sinnvoll, wenn das, womit Du da
> rechnest, abzählbar ist (wie z.B. Geldbeträge). Wenn Das kontinuierlich
> ist (Länge, Zeit, ...), dann ist FP-Arithmetik genau das richtige und Du
> solltest nicht versuchen, die Ergebnisse durch Runden "schöner" zu
> machen: Du bringst dadurch nur zusätzliche Fehler rein.

Sehr ausführlich und verständlich. Du hast mir sehr geholfen. Vielen Dank!

Schönen Abend noch.

Hasta luego, Stefan





[toc] | [prev] | [standalone]


Back to top | Article view | de.comp.lang.php


csiph-web