Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > de.comp.lang.php > #4428 > unrolled thread
| Started by | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| First post | 2018-11-15 01:23 +0100 |
| Last post | 2018-11-19 20:52 +0100 |
| Articles | 19 — 5 participants |
Back to article view | Back to de.comp.lang.php
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
| From | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| Date | 2018-11-15 01:23 +0100 |
| Subject | var_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]
| From | Arno Welzel <usenet@arnowelzel.de> |
|---|---|
| Date | 2018-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]
| From | Arno Welzel <usenet@arnowelzel.de> |
|---|---|
| Date | 2018-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]
| From | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| Date | 2018-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]
| From | "Christoph M. Becker" <cmbecker69@arcor.de> |
|---|---|
| Date | 2018-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]
| From | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| Date | 2018-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]
| From | "Christoph M. Becker" <cmbecker69@arcor.de> |
|---|---|
| Date | 2018-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]
| From | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| Date | 2018-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]
| From | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| Date | 2018-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]
| From | "Christoph M. Becker" <cmbecker69@arcor.de> |
|---|---|
| Date | 2018-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]
| From | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| Date | 2018-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]
| From | "Christoph M. Becker" <cmbecker69@arcor.de> |
|---|---|
| Date | 2018-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]
| From | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| Date | 2018-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]
| From | Claus Reibenstein <4spamersonly@kabelmail.de> |
|---|---|
| Date | 2018-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]
| From | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| Date | 2018-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]
| From | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| Date | 2018-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]
| From | "Christoph M. Becker" <cmbecker69@arcor.de> |
|---|---|
| Date | 2018-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]
| From | "Peter J. Holzer" <hjp-usenet3@hjp.at> |
|---|---|
| Date | 2018-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]
| From | Stefan Mayer <meniskus@gmx.net> |
|---|---|
| Date | 2018-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