challenge 16進数から10進数の変換

16進数を10進数に変換してください。

ただし、入出力は文字列とし、次の変換は最低必ずできなければいけないこととします。

  1. 0x12437308CCB6 →20080902065334

2.0x2C9C1227FC6520B →200904012311450123

あわせて、扱える最大の整数も明らかにしてください。

Posted feedbacks - HSP

文字列処理でごり押し。
速度の最適化はしていません。

理論上は無限桁の整数に対応していますが、メモリ・時間の誓約を加味すると……?
わたしのラップトップでは 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

Index

Feed

Other

Link

Pathtraq

loading...