重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

電子書籍の厳選無料作品が豊富!

値を10進、16進の相互変換を行いたいのですが、いまいちうまく行かずに困っています。
小さな桁数なら実現できているのですが、大きくすると変になります。
まず、10進→16進は作ることが出来ました。(計算機の16進変換と合っているので・・・)
10000081000008100000を16進にすると
8AC76CAFD29DA8A0になります。
で、今度は8AC76CAFD29DA8A0を10進にしたいのですがうまくいかないのです。
計算的にはこんな感じです。どこかおかしいですか?
0...1 * 0 = 0
A...16 * 10 = 160
8...256 * 8 = 2048
A...4096 * 10 = 40960
D...65536 * 13 = 851968
9...1048576 * 9 = 9437184
2...16777216 * 2 = 33554432
D...268435456 * 13 = 3489660928
F...4294967296 * 15 = 64424509440
A...68719476736 * 10 = 687194767360
C...1099511627776 * 12 = 13194139533312
6...17592186044416 * 6 = 105553116266496
7...281474976710656 * 7 = 1970324836974592
C...4503599627370500 * 12 = 54043195528446000
A...72057594037927900 * 10 = 720575940379279000
8...1152921504606850000 * 8 = 9223372036854800000
でこれを足すだけだと思ったのですが、
なぜかperlで一つずつ足すと10000081000008123880となります・・・

ここでexcelで検算をしてみたのですが、なぜか合いました。
0
160
2048
40960
851968
9437184
33554432
3489660928
64424509440
687194767360
13194139533312
105553116266496
1970324836974590
54043195528446000
720575940379279000
9223372036854800000
-----------------
10000081000008100000

でもおかしくないですか???1の位を手計算で足すとわかるのですが、
0になるわけが無いのです。
いったい何がどうなっているのか・・・

どうか助けてください。

A 回答 (6件)

>This is perl, v5.8.5 built for sun4-solaris


Excelで検算したとかあったのでWindows用のPerlだと思ってたのですが
Sparc Solarisのでしたか。

であれば、CPUの違いによる可能性もあるのでもし可能なら
Windowsのか、あるいは別のOS(x86用のものがたぶん望ましい)のもので
確かめられるのならやってみてください。

あと、bigintつかってても出力に pritnf使うとまずいです。たぶん。
bigint自体の文字列化のメソッドを使ってどうにかしてください。
    • good
    • 0

sakusaker7さま



> 今、5.8.8でも試してみましたが5.10.0のときと結果は同じでしたよ?

うう。何ででしょうか・・・


> 要は前回の回答でちょっと書いたように、本来15~6桁分しか正しく保持できないところに
> 10000081000008099840 という20桁の数値を食わせているからです。


BigIntを使っているのにダメなんでしょうか。

それともそもそも使い方が間違っていますでしょうか・・・



最後の足し算だけがおかしい感じなので、
10桁ずつ分けて計算して文字列として連結してしまえば
出来ることは出来るんですよね・・・

でもなんとなくwindows標準の電卓でも出来ることが
出来ないことに違和感を感じます。



>>sakusaker7さまの16進変換のアルゴリズムが私には理解できませんでした(恥
>そんなに小難しいことをやっているわけではないのですが(^^;
> こっちも説明が必要ですか?

下位の桁から
16の0乗 * 1の位
16の1乗 * 10の位



とやる方法しか知らなかったので、うーんどうやってるんだろう・・・と思いました。

あ、でも、またそれはよく勉強してみます!


いまは20桁の足し算が出来ない・・・って言うのをまずはナントカしたいです。





perlのバージョンを書いておきます。

########################################
perl -version

This is perl, v5.8.5 built for sun4-solaris

Copyright 1987-2004, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using `man perl' or `perldoc perl'. If you have access to the
Internet, point your browser at http://www.perl.com/, the Perl Home Page.
########################################
    • good
    • 0

今、5.8.8でも試してみましたが5.10.0のときと結果は同じでしたよ?


#use feature の行は削らないとダメですが、use warnings は
#5.8.8でも使えるはずなんですが…

で、質問者さんの計算結果と比べてみると

39062816406281640
625005062500506240 ← ここまでは同じ
10000081000008099840 ← でもここで160食い違いが

ということになってますね。
たぶん、
8AC76CAFD29DA8A0
の下から二桁目の'A'を別の数字に変えると、誤差はそれに応じて変わると思います。
要は前回の回答でちょっと書いたように、本来15~6桁分しか正しく保持できないところに
10000081000008099840 という20桁の数値を食わせているからです。

詳しい説明は今はちょっと書いている余裕がないので割愛。
#時間をくれれば書きますけど

>sakusaker7さまの16進変換のアルゴリズムが私には理解できませんでした(恥

そんなに小難しいことをやっているわけではないのですが(^^;
こっちも説明が必要ですか?
    • good
    • 0

sakusaker7さま、実は質問者です


(昨晩どうしても質問したかったのになぜかこのIDでログインが出来なくなり
 急遽新規のIDで質問した次第です・・・)

さて、教えてもらったコードを試したところ・・・なぜか違う結果になりました。
5.8だと結果が違ってしまうようですね。
ちなみに
use warnings;
use feature ':5.10';
の2行が、そんなのない、といわれてしまうのでコメントにしました。
8
138
2220
35527
568438
9095020
145520330
2328325295
37253204733
596051275730
9536820411689
152589126587037
2441426025392602
39062816406281640
625005062500506240
10000081000008099840

なぜか160足りない!(汗

実は既にBigIntは使っているのですが・・・何かがおかしいです。

sakusaker7さまの16進変換のアルゴリズムが私には理解できませんでした(恥

なので、オーソドックスにこんな感じにしてみました。
(変数超適当です。すみません)

#!/usr/local/bin/perl
use bigint;
my $hexstr = "8AC76CAFD29DA8A0";
my $i=0;
my $hoge=0;
foreach $b (reverse (split (//,$hexstr))){
$c=hex $b;
$test=$c * 16 ** $i;
print qq($b($c) * 16 ** $i =\n);
printf qq(%25.0f\n) ,$test;
$i++;
$hoge+=$test;
}
printf "%25.0f\n", $hoge;


<実行>
0(0) * 16 ** 0 =
0
A(10) * 16 ** 1 =
160
8(8) * 16 ** 2 =
2048
A(10) * 16 ** 3 =
40960
D(13) * 16 ** 4 =
851968
9(9) * 16 ** 5 =
9437184
2(2) * 16 ** 6 =
33554432
D(13) * 16 ** 7 =
3489660928
F(15) * 16 ** 8 =
64424509440
A(10) * 16 ** 9 =
687194767360
C(12) * 16 ** 10 =
13194139533312
6(6) * 16 ** 11 =
105553116266496
7(7) * 16 ** 12 =
1970324836974592
C(12) * 16 ** 13 =
54043195528445952
A(10) * 16 ** 14 =
720575940379279360
8(8) * 16 ** 15 =
9223372036854775808
10000081000008099840

あああああ!!!やっぱり160どこかに行ってしまいます。

で、ココで気を取り直して、上の計算結果を1の位、10の位、100の位と
計算してみたところ・・・

1の位・・・50
10の位・・・75
100の位・・・72

となり、どうやら、途中の桁ごとの計算はあっているようなのです。
  50
 75
72
--------
8000
(100の位までの計算結果。少なくとも10の位が4ではないはず。)


合計の計算がおかしいみたいです・・・
    • good
    • 0

桁が大きすぎますね。


もうちょっと小さい数字で試すといいと思います。

#!/usr/bin/perl
use strict;
use warnings;
use feature ':5.10';

my $hexstr = "8AC76CAFD29DA8A0";
my $acc = 0;

foreach my $digit (split q{}, $hexstr) {
#say $digit;
$acc = $acc * 16 + hex $digit;
#say $acc;
printf "%21.0f\n", $acc;
}

8
138
2220
35527
568438
9095020
145520330
2328325295
37253204733
596051275730
9536820411689
152589126587037
2441426025392602
39062816406281640
625005062500506240
10000081000008100000

“たまたま”正しい数字が出ていますが、精度としては15~16桁分しかないので
変換のやり方しだいで質問者さんのようにおかしな結果になることがあります。
んでまあ bigint とか使えばいいと思います。はい。
    • good
    • 0

差し支えなければ変換(両方向とも)のコードを見せてもらえますか?


たぶんオーバーフローしているんだと思います。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!