windows - ActiveState Perl 5.14 undlader at sammenligne visse værdier?

Indlæg af Hanne Mølgaard Plasc

Problem



Grundlæggende ved at bruge følgende kode i en fil stream får jeg følgende:


$basis = $2 * 1.0;
$cost = ($basis - 2500.0) ** 1.05;
# The above should ensure that both cost & basis are floats
printf "  \%f -> \%f", $basis, $cost;
if ($basis gt $cost) {  # <- *** THIS WAS MY ERROR: gt forces lexical!
    $cost = $basis;
    printf " -> \%f", $cost;
}


Udgange:


  10667.000000 -> 12813.438340
  30667.000000 -> 47014.045519
  26667.000000 -> 40029.842300
  66667.000000 -> 111603.373367 -> 66667.000000
  8000.000000 -> 8460.203780
  10667.000000 -> 12813.438340
  73333.000000 -> 123807.632158 -> 73333.000000
  6667.000000 -> 6321.420427 -> 6667.000000
  80000.000000 -> 136071.379474 -> 80000.000000


Som du kan se, synes koden for de fleste værdier at fungere fint.


Men for nogle værdier .... 66667, 80000, og et par andre, fortæller ActivePerl 5.14 mig, at 66667> 1111603 !!!


Er der nogen der ved noget om dette - eller har en alternativ Perl-tolk, jeg måske bruger (Windows). Fordi dette er latterligt.

Bedste reference


Du bruger en leksikalsk sammenligning i stedet for den numeriske


$cost = ($basis - 2500.0) ** 1.05;
printf "  \%f -> \%f", $basis, $cost;
if ($basis > $cost) {
    $cost = $basis;
    printf " -> \%f", $cost;
}


ps: revideret for at matche det opdaterede spørgsmål

Andre referencer 1


De første få kapitler af Learning Perl fjerner dette for dig. Skalære værdier kan være enten strenge eller tal, eller begge på samme tid. Perl bruger operatøren til at bestemme, hvordan man skal behandle dem. Hvis du vil lave numeriske sammenligninger, bruger du numeriske sammenligningsoperatører. Hvis du vil lave streng sammenligninger, bruger du streng sammenligning operatører.


Scalarværdierne selv har ikke en type, på trods af andre svar og kommentarer ved hjælp af ord som 'float' og 'cast'. Det er bare strenge og tal.

Andre referencer 2


Ikke sikker på hvorfor du skal sammenligne som leksikalsk, men du kan tvinge den ved hjælp af sprintf


$basis\_real = sprintf("\%015.6f",$basis);
$cost\_real = sprintf("\%015.6f",$cost);
printf "  \%s -> \%s", $basis\_real, $cost\_real;
if ($basis\_real gt $cost\_real) {
     $cost = $basis;
     printf " -> \%015.6f", $cost;
}


Produktion:


  00010667.000000 -> 00012813.438340
  00030667.000000 -> 00047014.045519
  00026667.000000 -> 00040029.842300
  00066667.000000 -> 00111603.373367
  00008000.000000 -> 00008460.203780
  00010667.000000 -> 00012813.438340
  00073333.000000 -> 00123807.632158
  00006667.000000 -> 00006321.420427 -> 00006667.000000
  00080000.000000 -> 00136071.379474


Grunden til at det ikke var som du bemærkede, sammenligner den leksikale sammenligning karakter til karakter, så når det rammer decimaltegnet i 6667., er det faktisk alfabetisk før 111603., så det er større.


For at rette op på dette skal du lave alle talene i samme størrelse, især hvor decimaltalmen er op. \% 015 er den samlede størrelse af antallet, herunder perioden og decimalerne.