PHPで10進数の値を62進数に変換するプログラムを下記URLを元に作ってみたのですが、値が大きいと62進数から10進数に戻した時に正確な値にならなくて困ってます。


具体的には、

5901894628545659904 (10進数)
  ↓
71YJSBTqsEC (62進数に変換)
  ↓
5901894628545659718 (10進数)

と値が異なってします。
INTの最大値9223372036854775807まで正常に扱いたいのですが、何か対策はありませんでしょうか?宜しくお願いします。

参考元:
https://gist.github.com/sunaoka/6362065
http://php.net/manual/ja/function.base-convert.php

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2014/08/05 19:12:38
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:a-kuma3 No.2

回答回数4971ベストアンサー獲得回数2153

ポイント250pt

dec2dohex() の方に、演算誤差があります。
floor() への引数が浮動小数点演算になるので、そこで有効桁が足りなくなります。

以下のように変更すれば、質問の数値でも正しく動作します。

<?php
function dec2dohex($dec) {
    $hashtable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $result = '';
    while($dec > 0) {
//      $result = $hashtable[$dec % 62] . $result;
//      $dec = floor($dec / 62);
        $mod = $dec % 62;
        $result = $hashtable[$mod] . $result;
        $dec = ($dec - $mod) / 62;
    }
    return $result;
}
?>

修正したソースで、演算の様子を var_dump すると、こうなります。

int(5901894628545659904)
string(11) "71YJSBTqsHC"
int(5901894628545659904)

元のコードでは、有効桁が途中で足りなくなるので、62進数の末尾が違ってきます。

id:wankodon

おお、これで問題なく動作しました。なるほど。
回答どうもありがとうございました。

2014/08/05 18:55:44

その他の回答1件)

id:sasada No.1

回答回数1482ベストアンサー獲得回数133

ポイント50pt

dohex2dec($dohex)のpowの演算が誤差を生んでるんですかねぇ

https://gist.github.com/sunaoka/6362065のfunction dohex2dec($dohex)の

  $result += $j * pow(62, $len - $i - 1);

  $result = $result * 62 + $j;

に変えてみてはいかがでしょうか。

id:wankodon

うーん、残念ながらダメでした。
ともあれ回答ありがとうございます。

2014/08/05 18:54:37
id:a-kuma3 No.2

回答回数4971ベストアンサー獲得回数2153ここでベストアンサー

ポイント250pt

dec2dohex() の方に、演算誤差があります。
floor() への引数が浮動小数点演算になるので、そこで有効桁が足りなくなります。

以下のように変更すれば、質問の数値でも正しく動作します。

<?php
function dec2dohex($dec) {
    $hashtable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $result = '';
    while($dec > 0) {
//      $result = $hashtable[$dec % 62] . $result;
//      $dec = floor($dec / 62);
        $mod = $dec % 62;
        $result = $hashtable[$mod] . $result;
        $dec = ($dec - $mod) / 62;
    }
    return $result;
}
?>

修正したソースで、演算の様子を var_dump すると、こうなります。

int(5901894628545659904)
string(11) "71YJSBTqsHC"
int(5901894628545659904)

元のコードでは、有効桁が途中で足りなくなるので、62進数の末尾が違ってきます。

id:wankodon

おお、これで問題なく動作しました。なるほど。
回答どうもありがとうございました。

2014/08/05 18:55:44

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません