日曜プログラミング

PHP好き集まれ〜!!

数値文字列比較

yukicoderというサイトで
数値文字列の比較で引っかかった部分があったのでメモしておきます。
No.201 yukicoderじゃんけん - yukicoder

問題を要約すると

名前A ポイントA じゃんけんの手
名前B ポイントB じゃんけんの手

というデータを受け取り、
ポイントAとBを比較して高いポイントの方の名前を出力するという
割りと簡単に出来そうな問題です。

ただPHPでやると少し厄介でした。。
テスト入力値を全くクリアできないんですよね。
PythonとかRubyみたいなイケイケな言語なら簡単に出来るんだろうなと思いながら
PHPで解いてみました。
あ、ちなみにイケイケってイケてるって意味じゃありません。数値比較得意そうな言語って意味です。


問題を見てすぐ解法は思い浮かぶと思います。
if文と比較演算子==,<,>を使えば余裕じゃん。みたいにね。

ただテストケースで584桁の入力値の場合がある場合には、これではダメでした。


"=="は、PHP5.4.4以降では
数値文字列を比較する場合にはintかfloatへキャストされて比較します。
その時に精度が落ちるような時は文字列比較してくれるそうです。
ちなみにこれは以下のブログを参考にしました。
PHP 5.4.4から==の挙動が一段と難しくなりました - hnwの日記

ただ、この問題では比較演算子">"や"<"が必要です。
この時に精度が落ちるようなキャストがされた時に文字列比較とはいきません。
そもそも意味がありませんよね。

ということでテストケースが584桁の数値のポイントを標準入力する必要があるこの問題では、精度が落ちまくります。
その結果、上手く行かないということになっていました。

BCMathというものを使えばできるらしいのですが、yukicoderで出来るのかどうか・・
./configureあたりからインストールしてないとダメっぽいし。

ということで以下のようなコードなら成功しました。
やってることは超単純です。
てかマジでこんなことしなければいけないのかと思ってやらなかったことです。
でも出来ました!

<?php
//データ取得
$input_a = explode(" ", trim(fgets(STDIN)));
$input_b = explode(" ", trim(fgets(STDIN)));
//$sa, $sbは名前。$pa, $pbはポイントです。
$sa = $input_a[0];
$sb = $input_b[0];
$pa = $input_a[1];
$pb = $input_b[1];

$pa_len = strlen($pa);
$pb_len = strlen($pb);

if($pa_len > $pb_len){
    echo $sa, PHP_EOL;
}else if($pa_len < $pb_len){
    echo $sb, PHP_EOL;
}else if($pa_len === $pb_len){
    $pa_arr = str_split($pa);
    $pb_arr = str_split($pb);
    for($i = 0; $i < count($pa_arr); $i++){
        $diff_arr[] = $pa_arr[$i] - $pb_arr[$i];
    }
    
    foreach($diff_arr as $value){
        if($value > 0){
            echo $sa, PHP_EOL;
            exit;
        }else if($value < 0){
            echo $sb, PHP_EOL;
            exit;
        }
    }
    echo "-1", PHP_EOL;
}

以上です。