16進数から10進数の変換
Posted feedbacks - Flatten
Nested Hidden変換対象の16進数文字列はコマンドライン引数から。
use bigint で使用されるMath::BigIntには ”Arbitrary size integer" って書いてあるので、任意長の整数を扱えるのではないかと思いますが。
1 2 | use bigint;
print "".hex shift;
|
速度の最適化はしていません。
理論上は無限桁の整数に対応していますが、メモリ・時間の誓約を加味すると……?
わたしのラップトップでは 150 桁まで確認できました。( *LOmake を使用 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | // ※負数は扱えない
// ※HSP3.2b2 のみ対応( strf, strtrim )
#module StrCalclator
#define true 1
#define false 0
#define ctype numrg(%1,%2,%3) \
( ((%2) <= (%1)) && ((%1) <= (%3)) )
//------------------------------------------------
// 数字 → 数値
//------------------------------------------------
#defcfunc charToNumber int chr
if ( numrg(chr, '0', '9') ) {
return chr - '0'
} else : if ( numrg(chr, 'a', 'z') ) {
return chr - 'a' + 10
} else : if ( numrg(chr, 'A', 'Z') ) {
return chr - 'A' + 10
}
return 0
//------------------------------------------------
// 数値 → 数字
//------------------------------------------------
#defcfunc numberToChar int n
if ( numrg(n, 0, 9) ) {
return n + '0'
} else : if ( numrg(n, 10, 36) ) {
return n + 'A'
} else {
return ' '
}
//------------------------------------------------
// 桁を大きい方にそろえる
//
// @ 足りない分は左側に0で詰めます
//------------------------------------------------
#deffunc Str_toSamePlaces var p1, var p2, local len, local sResult
len = strlen(p1), strlen(p2)
if ( len(0) == len(1) ) {
} else : if ( len(0) > len(1) ) {
p2 = strf("%0"+ len(0) +"s", p2)
len(1) = len(0)
} else {
p1 = strf("%0"+ len(1) +"s", p1)
len(0) = len(1)
}
return len(0)
//------------------------------------------------
// 文字列同士の加法
//------------------------------------------------
#defcfunc StrCalc_add str p1, str p2, \
local sLeft, local sRight, local sResult, \
local cntRoundUp, local places, local n, local c
sLeft = p1
sRight = p2
cntRoundUp = 0 // 繰り上がり (適当英単語)
// 桁を大きい方にそろえる
Str_toSamePlaces sLeft, sRight
places = stat
sdim sResult, places + 1
// 桁ごとの足し算
for i, places - 1, -1, -1 // 後ろの桁からの減数ループ
// 桁の数値を得る
c(0) = peek(sLeft, i)
c(1) = peek(sRight, i)
n(0) = charToNumber(c(0))
n(1) = charToNumber(c(1))
// 繰り上がりを考慮して足し算する
n(2) = n(0) + n(1) + cntRoundUp
cntRoundUp = 0
// 繰り上がり?
if ( n(2) >= 10 ) {
cntRoundUp ++
n(2) -= 10
}
c(2) = numberToChar(n(2))
// 結果に書き込む
poke sResult, i, c(2)
next
// 最後の繰り上がり
if ( cntRoundUp ) {
sResult = strf("%c", numberToChar(cntRoundUp)) + sResult
}
return sResult
//------------------------------------------------
// 文字列同士の乗法
//------------------------------------------------
#defcfunc StrCalc_mul str p1, str p2, \
local sLeft, local sRight, local sMiddle, local sResult, \
local cntRoundUp, local places, local n, local c
sLeft = p1
sRight = p2
places = strlen(sLeft), strlen(sRight)
sdim sResult, places * 2
sdim sMiddle, places + 1, places // 途中式
// 右辺の桁ごとにループ
repeat places(1)
c(1) = peek(sRight, places(1) - cnt - 1)
n(1) = charToNumber(c(1))
if ( n(1) == 0 ) {
sMiddle(cnt) = "0"
continue
}
cntRoundUp = 0 // 繰り上がり (適当英単語)
// 桁ごとのかけ算
for i, places(0) - 1, -1, -1 // 後ろの桁からの減数ループ
// 桁の数値を得る
c(0) = peek(sLeft, i)
n(0) = charToNumber(c(0))
// 繰り上がりを考慮してかけ算する
n(2) = n(0) * n(1) + cntRoundUp
cntRoundUp = 0
repeat
if ( n(2) >= 10 ) {
cntRoundUp ++
n(2) -= 10
} else {
break
}
loop
c(2) = numberToChar(n(2))
// 途中式に書き込む
poke sMiddle(cnt), i, c(2)
next
// 最後の繰り上がり
if ( cntRoundUp ) {
sMiddle(cnt) = strf("%c%s", numberToChar(cntRoundUp), sMiddle(cnt))
}
// 後ろ側に 0 を並べて桁揃え
sMiddle(cnt) += strf("%0"+ cnt +"s", "")
loop
// 途中式をすべて足し合わせる
repeat places(1)
sResult = StrCalc_add(sResult, sMiddle(cnt))
loop
return sResult
//------------------------------------------------
// 文字列の累乗
//------------------------------------------------
#defcfunc StrCalc_pow str p1, int p2, local sResult
sdim sResult
sResult = "1"
repeat p2
sResult = StrCalc_mul(sResult, p1)
loop
return sResult
//------------------------------------------------
// 10進数以外の基数の文字列を10進数文字列に変換
//
// @ 2 ~ 32 進数まで保証
// @ 負数は扱えない
//------------------------------------------------
#defcfunc StrCalc_toDigit str p1, int fromRadix, \
local sFromRadix, local sInput, local sDigit
if ( fromRadix <= 0 ) { return "" } // エラー
if ( fromRadix == 10 ) { return p1 } // 変換する必要なし
sdim sInput, 320
sdim sDigit, 320
sFromRadix = str(fromRadix)
// 小文字にする
sInput = p1
places = strlen(sInput)
// 十進数に直す
repeat places
c = peek(sInput, places - (cnt + 1))
stmp = StrCalc_mul( str( charToNumber(c) ), StrCalc_pow(sFromRadix, cnt) )
sDigit = StrCalc_add( sDigit, stmp )
loop
return sDigit
#global
*main
sLeft = "12437308CCB6", "2C9C1227FC6520B", "ff"
sResult = "20080902065334", "200904012311450123", "255"
repeat 3
mes "#"+ cnt +"\n解答:"+ StrCalc_toDigit(sLeft(cnt), 16) +"\n正答:"+ sResult(cnt)
mes
loop
stop
// おまけ
*LOmake
n = 15 // 入力する16進数の桁数の10分の1
sdim sHex, 1024
repeat n
sHex += "1234567890"
loop
sDig = StrCalc_toDigit(sHex, 16)
logmes sDig
stop
|
Squeak Smalltalk で。
Integer のクラスメソッド #readFrom:base: は、第一引数に変換したい文字列のストリームを、第二引数に何進数か指定してコールすることで十進数への変換が可能です。
桁数の制約は特にありません。
なお、文字列の先頭に16進数リテラル記述であることを示す '16r' が付けてある場合は、当該文字列にメッセージ asNumber を送るだけで済ませることもできます。
もちろんリテラルであれば、変換操作自体必要ありません。
1 2 3 4 5 6 7 8 | Integer readFrom: '12437308CCB6' readStream base: 16 "=> 20080902065334 "
Integer readFrom: '2C9C1227FC6520B' readStream base: 16 "=> 200904012311450123 "
'16r12437308CCB6' asNumber "=> 20080902065334 "
'16r2C9C1227FC6520B' asNumber "=> 200904012311450123 "
16r12437308CCB6 "=> 20080902065334 "
16r2C9C1227FC6520B "=> 200904012311450123 "
|
String#hex メソッドで変換ができます。 標準入力から入力された値を変換する場合には、以下のようにすればできます。
1 | p ARGV.map{|s|s.hex}
|
1 | main = interact $ unlines . map (show . (read :: String -> Integer)) . lines
|
.NETだとConvertクラスが異常に強力なのでこれでいけます。 取り扱える最大値について、int64.MaxValueから取得できる値が限界となります。 ※ 当然これ以上に大きい値ではOverflowExceptionがでます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | static void Main(string[] args)
{
Console.WriteLine(ConvertTo16("12437308CCB6"));
Console.WriteLine(ConvertTo16("2C9C1227FC6520B"));
Console.WriteLine(ConvertTo16(Convert.ToString(Int64.MaxValue, 16)));
Console.ReadLine();
}
static long ConvertTo16(string hexstr)
{
return Convert.ToInt64(hexstr, 16);
}
//20080902065334
//200904012311450123
//9223372036854775807
|
ConvertTo16じゃなく、ConvertFrom16にすべきな挙句、.NETなのにotherにしてしまった…orz
1 2 3 | (define (hex->dec h)
(number->string
(string->number h 16)))
|
変換機能は組み込みでありますが、内部的にはdouble型なのでdouble型のビット長(通常64bit)を超えると結果がおかしくなってしまいます。
gmpライブラリーを使うと任意の多倍長整数が扱えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # builtin
> 0x12437308CCB6
[1] 20080902065334
> 0x2C9C1227FC6520B
[1] 200904012311450112
> typeof(0x2C9C1227FC6520B)
[1] "double"
# gmp
> library(gmp)
> as.bigz("0x12437308CCB6")
[1] "20080902065334"
> as.bigz("0x2C9C1227FC6520B")
[1] "200904012311450123"
|
Python 2.4
コマンドライン引数から16進数文字列を入力。
int関数で変換しています。
int型の範囲に収まらなければ自動的にlong型になり、long型には桁数の制限がないようです。
1 2 | import sys
print int(sys.argv[1], 16)
|
PHP 5.1.6 hexdec()ではinteger型の範囲をこえる数値は、float型で返すみたいなので、 gmp_strval()を使いました。
see: PHP Manual - hexdec
1 2 3 4 5 6 7 8 9 10 11 | // hexdec() ※うまくいかない
$ php -r 'echo hexdec($argv[1]),"\n";' 0x12437308CCB6
20080902065334
$ php -r 'echo hexdec($argv[1]),"\n";' 0x2C9C1227FC6520B
2.0090401231145E+17
// gmp_strval()
$ php -r 'echo gmp_strval($argv[1]),"\n";' 0x12437308CCB6
20080902065334
$ php -r 'echo gmp_strval($argv[1]),"\n";' 0x2C9C1227FC6520B
200904012311450123
|
F#で、入力HEX文字列は、コマンドライン引数で指定します。 uint64 の範囲で実行可 実行例: >hex2dec 0x12437308ccb6 20080902065334 >hex2dec 0x2c9c1227fc6520b 200904012311450123
1 2 3 4 5 6 7 8 9 10 11 12 13 | #light
open System
[<STAThread>]
[<EntryPoint>]
let main(args) =
match args with
| [|hexString|] ->
printfn "%u" <| uint64 hexString
| _ ->
printfn "Usage Hex2dec hexString"
0
|
コマンドから実行。 Longの方がスマートですが、0x7fffffffffffffffまでの制限ありです。 BigIntegerは事実上無制限のようです。 BigDecimal -OKWave <http://74.125.153.132/search?q=cache:fEYO5fTGEsoJ:okwave.jp/qa715480.html+java+biginteger+%E6%9C%80%E5%A4%A7&cd=13&hl=ja&ct=clnk&gl=jp>
1 2 | groovy -e "println Long.decode(args[0])" 0x12437308CCB6
groovy -e "println new BigInteger(args[0] - ~/0x/, 16)" 0x2C9C1227FC6520B
|
引数は、コマンドラインで指定します。 短い桁数の計算に分解しているので、特に制限はありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | use strict;
my $base = "0123456789abcdef";
my $num_16 = shift; $num_16 =~ s/^0x//; $num_16 = "\L$num_16";
my @num_16 = reverse split //, $num_16;
my @result;
foreach my $idx (0 .. $#num_16) {
my $n = index($base, $num_16[$idx]);
next unless $n;
my @temp = calc($n, $idx);
foreach my $idx (0 .. $#temp) {
$result[$idx] += $temp[$idx];
if ($result[$idx] > 9) {
$result[$idx] -= 10; $result[$idx + 1]++;
}
}
}
print reverse(@result), "\n";
sub calc {
my @work = reverse split //, shift(); my $x = shift;
while ($x--) {
$_ = $_ * 16 foreach @work;
foreach my $idx (0 .. $#work) {
if ($work[$idx] > 9) {
my ($up, $n) = $work[$idx] =~ /^(.+)(.)$/;
$work[$idx] = $n; $work[$idx + 1] += $up;
}
}
if ($work[$#work] > 9) {
my ($m, $n) = $work[$#work] =~ /^(.+)(.)$/;
$work[$#work] = $n; push @work, reverse(split //, $m);
}
}
return @work;
}
|
BigIntegerで。BigIntegerは任意精度なので上限はありません。
1 2 3 4 5 6 7 | import java.math.BigInteger;
public class ToDecimal {
public static void main(String[] args) {
System.out.println(new BigInteger(args[0].replaceFirst("^0x", ""), 16).toString());
}
}
|
BigIntを使って書いてみました。内部的にBigIntegerが使われているので特に上限はありません。
1 | println(BigInt(args.first.replaceFirst("^0x", ""), 16).toString)
|
strtoull で変換し、printf の %ull で出力するのが標準かと。
VC2008EE と gcc(MinGW) で確認しました。
see: HeadWing | 64bit Integer in MinGWC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER
#define strtoull _strtoui64
#endif
#ifdef __MINGW32__
#define FORMAT_LLU "%I64u"
#else
#define FORMAT_LLU "%llu"
#endif
int main(void) {
char buf[128];
memset(buf, 0x00, sizeof(buf));
if ( fgets(buf, sizeof(buf), stdin) ) {
unsigned long long ll;
ll = strtoull(buf, NULL, 16);
printf(FORMAT_LLU, ll);
}
return 0;
}
|
書き忘れましたが、扱える整数の幅は符号なし64bitなので、 0 ~ 18446744073709551615 です。
1 2 | let [|hex_string|] = Sys.argv;;
print_endline (Int64.to_string (Int64.of_string hex_string));;
|
F# で、Math.BigInt を使って桁の制限をなくしたバージョン 実行例: > hex2dec "0x12437308CCB6";; val it : Math.BigInt = 20080902065334I > hex2dec "0x2C9C1227FC6520B";; val it : Math.BigInt = 200904012311450123I
1 2 3 4 5 6 7 8 | #light
let hex2dec (s:string) =
let hs = s.[2..] //先頭の0x を取り除く
let intToBigInt (x:int) = Math.BigInt(x)
let bs = 16I
let times_base x y = x * bs + y
Seq.fold times_base 0I <| Seq.map (intToBigInt << int << (^) "0x" << string) hs
|
また、標準で#xというリーダーマクロが定義されていますので、これを用いて直接的に表記することも可能です。
1 2 3 4 5 6 7 8 9 10 | (parse-integer "12437308CCB6" :radix 16)
;=> 20080902065334
12
(parse-integer "2C9C1227FC6520B" :radix 16)
;=> 200904012311450123
15
(list #x12437308CCB6 #x2C9C1227FC6520B)
;=> (20080902065334 200904012311450123)
|
上限について書き忘れました。 Common Lispでは整数の大きさについて制限は設けられていません。 http://www.lispworks.com/documentation/HyperSpec/Body/t_intege.htm
hex2dec '12437308CCB6' 20080902065334 hex2dec '2C9C1227FC6520B' 200904012311450123 hex2dec 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' 340282366920938463463374607431768211455 (2x^128)-1 340282366920938463463374607431768211455
1 | hex2dec =: 16x #. '0123456789ABCDEF' i. ]
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | /* --------------------------------------------------------------------------- */
String.prototype.toCharArray=function(){
var arr = new Array(this.length);
for(var i = 0; i < this.length; i++){ arr[i] = this.charAt(i); };
return arr;
};
/* --------------------------------------------------------------------------- */
function add(strnum1, strnum2){
var arr1 = strnum1.toCharArray().reverse();
var arr2 = strnum2.toCharArray().reverse();
var max = (arr1.length > arr2.length ? arr1.length : arr2.length) - 1;
var strsum = "";
for(var i = 0, up = 0; i <= max; i++){
var c1 = i < arr1.length ? parseInt(arr1[i],10) : 0;
var c2 = i < arr2.length ? parseInt(arr2[i],10) : 0;
c1 += up;
c1 += c2;
up = Math.floor(c1/10);
c1 %= 10;
strsum = c1 + strsum;
if(i == max) strsum = up+strsum;
}
return strsum;
};
/* --------------------------------------------------------------------------- */
function sum(arr){
var strsum = "";
for(var i = 0; i < arr.length; i++){
strsum = add(strsum, arr[i]);
}
return strsum.replace(/^0*/,"");
};
/* --------------------------------------------------------------------------- */
function multiple(a, b){
var arr_a = a.toCharArray().reverse();
var arr_b = b.toCharArray().reverse();
var arr_c = new Array(arr_b.length);
var max = arr_a.length-1;
for(var i = 0, zeropad=""; i < arr_b.length; i++,zeropad+="0"){
var str_c = "";
for(var j = 0, up=0; j<arr_a.length; j++){
var c = (parseInt(arr_a[j], 10) * parseInt(arr_b[i],10));
c+=up;
up = Math.floor(c/10);
c %= 10;
str_c = c+str_c;
if(j==max && up>0) str_c=up+str_c;
}
str_c+=zeropad;
arr_c[i] = str_c;
}
return sum(arr_c);
};
/* --------------------------------------------------------------------------- */
function hex2decimal(hexstr){
var template = "0123456789ABCDEF";
var arr = hexstr.toUpperCase().substring(2).toCharArray().reverse();
for(var i = 0, hex="1"; i < arr.length; i++, hex=multiple(hex,"16")){
var numc = "" + template.indexOf(arr[i]);
var mult = multiple(numc, hex);
arr[i] = mult;
}
var decstr=sum(arr);
if(decstr.length==0) desctr="0";
return decstr;
};
|
リンク貼るの失敗してますたorz
また、最大値について、「変換後の値がNumber.MAX_VALUE桁となる値」と修正します。
see: 検証用ページ
言語組み込みで扱える最大整数は64bitのlongです。なぜか標準ライブラリに16進文字列から整数に変換する関数がないのでC99からstrtollを借ります。
標準ライブラリに多倍長整数はあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import core.stdc.stdlib: strtoll;
import std.bigint: BigInt;
import std.stdio;
void main() {
// longは64bit
long x = strtoll("0x12437308CCB6", null, 16);
writeln(x); // 20080902065334
// BigIntは多倍長整数
BigInt y = "0x2C9C1227FC6520B";
writeln(y); // 200904012311450123
}
|
1 2 3 4 5 6 7 8 | #include <iostream>
int main()
{
unsigned long long n;
std::cin >> std::hex >> n;
std::cout << n << std::endl;
}
|
SQL Server 2008 で確認しました。 最大値は、bigint の限界なので、9,223,372,036,854,775,807 です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | WITH
InputStrs(id, hex) AS (
SELECT 1, '0x12437308CCB6'
UNION ALL
SELECT 2, '0x2C9C1227FC6520B'
)
, HexStrs(id, hex) AS (
SELECT
id
, SUBSTRING(hex, 3, LEN(hex))
FROM
InputStrs
)
, MaxLen(max_len) AS (
SELECT MAX(LEN(hex)) FROM HexStrs
)
, Seq(id, n) AS (
SELECT id, 1 FROM HexStrs
UNION ALL
SELECT
Seq.id
, n + 1
FROM
Seq INNER JOIN HexStrs ON Seq.id = HexStrs.id
WHERE
n + 1 <= (SELECT max_len FROM MaxLen)
)
, Chs(id, ch, i) AS (
SELECT
id
, SUBSTRING(hex, LEN(hex), 1)
, 1
FROM
HexStrs
UNION ALL
SELECT
Chs.id
, SUBSTRING(hex, LEN(hex) - Chs.i, 1)
, i + 1
FROM
Chs
INNER JOIN HexStrs ON Chs.id = HexStrs.id
WHERE
i < (SELECT max_len FROM MaxLen)
)
SELECT
SUM(CASE
WHEN ch = ''
THEN 0
WHEN ch LIKE '[A-F]'
THEN ASCII(ch) - ASCII('A') + 10
ELSE CAST(ch AS int)
END * POWER(CAST(16 AS bigint), i - 1))
FROM
Chs
GROUP BY
id
|
Rubyでは数値リテラルとして16進整数表現があるので、そのまま文字列をevalすれば望む値が得られます。出力も文字列という出題なので、to_sで文字列にしています。
ちなみにRuby自体には「最大の整数」という制限はなく、メモリの許す限り大きな整数を扱うことができます。
see: Integer - Rubyリファレンスマニュアル
1 2 | p eval("0x12437308CCB6").to_s #=> "20080902065334"
p eval("0x2C9C1227FC6520B").to_s #=> "200904012311450123"
|
最大の整数は実装依存ですが、私の64bitマシンでは2^63-1が最大です。
1 2 3 4 5 6 7 8 9 | h2i(){
local -i i
if [[ "$1" == 0x* ]]; then
i="$1"
else
i=16#"$1"
fi
echo $i
}
|
有理数モードにすると桁数の制限がなくなるが 対応している演算は四則演算とべき乗だけである。 BVAL関数をそのまま使うと最初のサンプルは、うまくいくが 2番目のサンプルでは精度が足りない。 そこで、1桁ごとに分解して集計した。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | OPTION ARITHMETIC RATIONAL
FUNCTION hex2dec$(h$)
LET n = LEN(h$)
LET t = 0
FOR i = 0 TO n - 1
LET t = t + BVAL(h$(n - i : n - i),16) * 16 ^ i
NEXT I
LET hex2dec$ = STR$(t)
END FUNCTION
PRINT hex2dec$("12437308CCB6") !=>20080902065334
PRINT hex2dec$("2C9C1227FC6520B") !=>200904012311450123
END
|
1 2 3 4 5 6 | import std.stdio;
void main() {
long x = mixin("0x12437308CCB6");
writeln(x); // 20080902065334
}
|
処理系の整数の大きさに制限がないことと、そのプログラムで扱える最大の整数、つまり正しく変換される上限が、同じだと、なぜ考えうるのかよく判りませんがLispって、そういうものなんですね。なるほど。
XPath1.0の数値型は浮動小数点数しか存在せず、その精度は処理系によって異なるようです。倍精度くらいで実装されているようで、この数値型をそのまま利用すると(29-51行)、条件2の変換が正確に行えませんでした。
そこで、入力された16進数を上位ビットと下位ビットに分けて数値化し、10進数として表示する時に2つの数を合成する手法を用いました(52-95行)。それでもFirefoxだと16桁でヘタってしまいましたが、Xalanは26桁まで頑張ってくれました。
実行結果(実行方法:適当なXMLにこのXSLTを適用)
- Firefox 3.5.1:
0x12437308CCB6 = 20080902065334.
0x2C9C1227FC6520B = 200904012311450100.
0x12437308CCB6 = (bignum) 20080902065334.
0x2C9C1227FC6520B = (bignum) 200904012311450123.
0xCDEF89AB45670123 = (bignum) 14839230665905865403.
0x112233445566778899AABBCCDD = (bignum) 1357463230989497420518412782813.
- Xalan 1.10.0:
0x12437308CCB6 = 20080902065334.
0x2C9C1227FC6520B = 200904012311450112.
0x12437308CCB6 = (bignum) 20080902065334.
0x2C9C1227FC6520B = (bignum) 200904012311450123.
0xCDEF89AB45670123 = (bignum) 14839230665905864995.
0x112233445566778899AABBCCDD = (bignum) 1357463230989497419223659171037.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | <?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:variable name="var" select="document('')/xsl:stylesheet/xsl:template[@name='var']" />
<xsl:template match="/">
<xsl:variable name="test1" select="'0x12437308CCB6'" />
<xsl:variable name="test2" select="'0x2C9C1227FC6520B'" />
<xsl:variable name="test3" select="'0xCDEF89AB45670123'" />
<xsl:variable name="test4" select="'0x112233445566778899AABBCCDD'" />
<xsl:call-template name="hex2dec">
<xsl:with-param name="input" select="$test1" />
</xsl:call-template>
<xsl:call-template name="hex2dec">
<xsl:with-param name="input" select="$test2" />
</xsl:call-template>
<xsl:call-template name="bighex2dec">
<xsl:with-param name="input" select="$test1" />
</xsl:call-template>
<xsl:call-template name="bighex2dec">
<xsl:with-param name="input" select="$test2" />
</xsl:call-template>
<xsl:call-template name="bighex2dec">
<xsl:with-param name="input" select="$test3" />
</xsl:call-template>
<xsl:call-template name="bighex2dec">
<xsl:with-param name="input" select="$test4" />
</xsl:call-template>
</xsl:template>
<xsl:template name="hex2dec">
<xsl:param name="input" />
<xsl:value-of select="$input" /> = <!--
--><xsl:apply-templates select="$var" mode="translate">
<xsl:with-param name="input" select="substring($input,3)" />
</xsl:apply-templates>.
<!--
--></xsl:template>
<xsl:template match="xsl:template" mode="translate">
<xsl:param name="input" />
<xsl:param name="output" select="0" />
<xsl:choose>
<xsl:when test="$input=''">
<xsl:value-of select="$output" />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="." mode="translate">
<xsl:with-param name="input" select="substring($input,2)" />
<xsl:with-param name="output" select="$output * 16 + hex[@name=substring($input,1,1)]" />
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="bighex2dec">
<xsl:param name="input" />
<xsl:variable name="partition" select="floor((string-length($input)-2) div 2)" />
<xsl:value-of select="$input" /> = (bignum) <!--
--><xsl:apply-templates select="$var" mode="btranslate">
<xsl:with-param name="input" select="substring($input,3,$partition)" />
<xsl:with-param name="input2" select="substring($input,3+$partition)" />
</xsl:apply-templates>.
<!--
--></xsl:template>
<xsl:template match="xsl:template" mode="btranslate">
<xsl:param name="input" select="''" />
<xsl:param name="input2" select="''" />
<xsl:param name="output" select="0" />
<xsl:param name="output2" select="0" />
<xsl:variable name="in1" select="substring($input,1,1)" />
<xsl:choose>
<xsl:when test="$input=''">
<xsl:choose>
<xsl:when test="$input2=''">
<xsl:variable name="outA" select="substring($output,1,string-length($output)-string-length($output2))" />
<xsl:variable name="outB" select="substring($output,string-length($output)-string-length($output2)+1) + $output2" />
<xsl:variable name="overflow" select="number(string-length($outB)>string-length($output2))" />
<xsl:value-of select="$outA + $overflow" />
<xsl:value-of select="substring($outB,1+$overflow)" />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="." mode="btranslate">
<xsl:with-param name="input2" select="substring($input2,2)" />
<xsl:with-param name="output" select="$output*16" />
<xsl:with-param name="output2" select="$output2 * 16 + hex[@name=substring($input2,1,1)]" />
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="." mode="btranslate">
<xsl:with-param name="input" select="substring($input,2)" />
<xsl:with-param name="input2" select="$input2" />
<xsl:with-param name="output" select="$output * 16 + hex[@name=substring($input,1,1)]" />
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="text()" mode="translate" />
<xsl:template match="text()" mode="btranslate" />
<xsl:template match="text()" />
<xsl:template name="var">
<hex name="0">0</hex>
<hex name="1">1</hex>
<hex name="2">2</hex>
<hex name="3">3</hex>
<hex name="4">4</hex>
<hex name="5">5</hex>
<hex name="6">6</hex>
<hex name="7">7</hex>
<hex name="8">8</hex>
<hex name="9">9</hex>
<hex name="A">10</hex>
<hex name="B">11</hex>
<hex name="C">12</hex>
<hex name="D">13</hex>
<hex name="E">14</hex>
<hex name="F">15</hex>
</xsl:template>
</xsl:stylesheet>
|
arc> (hex2dec "12437308CCB6") "20080902065334" arc> (hex2dec "2C9C1227FC6520B") "200904012311450123" 扱える整数については制限はありません。
1 | (def hex2dec (x) (string (coerce x 'int 16)))
|





shojiHIDAKA #8955() Rating1/1=1.00
16進数を10進数に変換してください。
ただし、入出力は文字列とし、次の変換は最低必ずできなければいけないこととします。
2.0x2C9C1227FC6520B →200904012311450123
あわせて、扱える最大の整数も明らかにしてください。
[ reply ]