source: trunk/Include/Classes/ActiveBasic/Strings/SPrintF.ab@ 355

Last change on this file since 355 was 355, checked in by イグトランス (egtra), 17 years ago

FormatIntegerDを実装。
UnitTestの失敗時の表示を目立つようにした。
ArrayListを名前空間System.Collectionsに入れた。

File size: 7.1 KB
RevLine 
[335]1'Classes/ActiveBasic/Strings/SPrintF.ab
2
3Namespace ActiveBasic
4Namespace Strings
5
6Namespace Detail
7
8/*!
9@brief 浮動小数点数を文字列化する低水準な関数。符号、指数、仮数に分けて出力。
10@author Egtra
11@date 2007/09/18
12@param[in] x 文字列化する浮動小数点数
13@param[out] e 指数
14@param[out] sign 符号
15@return 仮数
16仮数は1の位から下へ17桁で、小数点を含まない。そのため、誤差を無視すればVal(仮数) * 10 ^ (e - 17) = Abs(x)が成り立つ。
17
18xに無限大、無限小、非数を渡した場合の動作は未定義。
19*/
20Function FloatToChars(x As Double, ByRef e As Long, ByRef sign As Boolean) As String
21 Imports System
22
23 '0を弾く
24 If x = 0 Then
25 If GetQWord(VarPtr(x) As *QWord) And &h8000000000000000 Then
26 sign = True
27 Else
28 sign = False
29 End If
30
31 e = 0
32 FloatToChars = "00000000000000000"
33 Exit Function
34 End If
35
36 '符号の判断(同時に符号を取り除く)
37 If x < 0 Then
38 sign = True
39 x = -x
40 Else
41
42 sign = False
43 End If
44
45 '1e16 <= x < 1e17へ正規化
46 '(元のx) = (正規化後のx) ^ (d - 17)である。
47 Dim d = Math.Floor(Math.Log10(x)) As Long
48 If d < 16 Then
49 x *= ipow(10, +17 - d)
50 ElseIf d > 16 Then
51 x /= ipow(10, -17 + d)
52 End If
53
54 '補正
55 While x < 1e16
56 x *= 10
57 d--
58 Wend
59 While x >= 1e17
60 x /= 10
61 d++
62 Wend
63
64 d--
65 e = d
66
67 FloatToChars = Str$(x As QWord)
68End Function
69
70/*!
71@brief 書式化関数群で使用するフラグ。
72@author Egtra
73@date 2007/09/18
74*/
75Const Enum FormatFlags
76 '! 何も指定がない。
77 None = &h0
78 '! 符号、+。符号付変換[diAaEeFfGg]のとき、正の値でも符号を付ける。
79 Sign = &h1
80 /*! 空白、空白文字。
81 符号付変換[diAaEeFfGg]のとき、正の値ならば符号分の空白を開ける。Signが立っているときには無視される。
82 */
83 Blank = &h2
84 /*! ゼロ、0。
85 [diouXxAaEeFfGg]で、フィールドの空きを0で埋める。leftが立っているときには無視される。
86 */
87 Zero = &h4
88 '! 左揃え、-。フィールド内で左揃えにする。
89 Left = &h8
90 /*! 代替表記、#。
91 <ul>
92 <li>[OoXx]では、数値の先頭に0、0xを付ける。</ul>
93 <li>[AaEeFfGg]では、精度0でも小数点を付ける。</ul>
94 <li>[Gg]では、それに加え、小数部末尾の0の省略を行わないようにする。</ul>
95 </ul>
96 */
97 Alt = &h10
98 '! 大文字。使用するアルファベットを大文字にする。[aefgx]を[AEFGX]化する。
99 Cap = &h20
100End Enum
101
102/*!
103@brief 浮動小数点数をprintfの%e, %E相当の変換で文字列化する関数。
104@author Egtra
105@date 2007/09/18
106@param[in] x 文字列化する浮動小数点数値。
107@param[in] d 精度。小数点以下の桁数。DWORD_MAXのとき、指定なしとして既定値6となる。
108@param[in] field フィールド幅。
109@param[in] flags 書式フラグ。
110@return xの文字列表現
111
112@todo 末尾桁四捨五入
113*/
114Function FormatFloatE(x As Double, d As DWord, field As DWord, flags As FormatFlags) As String
115 Dim sb = New System.Text.StringBuilder
116 With sb
117 If d = DWORD_MAX Then
118 d = 6
119 End If
120
[355]121 Dim e As Long, negative As Boolean
122 Dim s = FloatToChars(x, e, negative)
[335]123
[355]124 If negative Then
[335]125 .Append("-")
126 Else
127 If flags And Sign Then
128 .Append("+")
129 ElseIf flags And Blank Then
130 .Append(" ")
131 End If
132 End If
133
134 .Append(s[0])
135
136 If (flags And Alt) Or d > 0 Then
137 .Append(".")
138 Dim outputLen = s.Length - 1
139 If outputLen >= d Then
140 .Append(s, 1, d)
141 Else 'sで用意された桁が指定された精度より少ないとき
142 .Append(s, 1, outputLen)
143 .Append(&h30 As StrChar, d - outputLen) '足りない桁は0埋め
144 End If
145 End If
146
147 If flags And Cap Then
148 .Append("E")
149 Else
150 .Append("e")
151 End If
152
[355]153 .Append(FormatIntegerD(e, 2, 0, Sign Or Zero))
[335]154
[355]155 AdjustFieldWidth(sb, field, negative, flags)
[335]156 End With
157 FormatFloatE = sb.ToString()
158End Function
159
160'! DWordの最大値4294967295の文字数 - 1。FormatIntegerU内で使用。
[355]161Const MaxSizeU = 9
[335]162
163/*!
164@brief 符号無し整数をprintfの%u相当の変換で文字列化する関数。
165@author Egtra
166@date 2007/09/18
167@param[in] x 文字列化する整数値。
168@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
169@param[in] field フィールド幅。
170@param[in] flags 書式フラグ。
171@return xの文字列表現
172*/
173Function FormatIntegerU(x As DWord, d As DWord, field As DWord, flags As FormatFlags) As String
[355]174 FormatIntegerU = FormatInteger(x, d, field, flags, 0)
175End Function
[335]176
[355]177'! Longの最大値2147483647, -2147483648の符号部を除く文字数 - 1。FormatIntegerU内で使用。
178Const MaxSizeD = 9
179
180/*!
181@brief 符号有り整数をprintfの%u相当の変換で文字列化する関数。
182@author Egtra
183@date 2007/10/13
184@param[in] x 文字列化する整数値。
185@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
186@param[in] field フィールド幅。
187@param[in] flags 書式フラグ。
188@return xの文字列表現
189*/
190Function FormatIntegerD(x As Long, d As DWord, field As DWord, flags As FormatFlags) As String
191 Dim dwX As DWord
192
193 Dim signChar As StrChar
194 If x < 0 Then
195 dwX = (-x) As DWord
196 signChar = Asc("-")
197 Else
198 dwX = x As DWord
199 If flags And Sign Then
200 signChar = Asc("+")
201 ElseIf flags And Blank Then
202 signChar = Asc(" ")
203 End If
204 End If
205
206 FormatIntegerD = FormatInteger(dwX, d, field, flags, signChar)
207End Function
208
209/*!
210@brief 整数をprintfの%d, %u相当の変換で文字列化する関数。
211@author Egtra
212@date 2007/09/18
213@param[in] x 文字列化する整数値。
214@param[in] d 精度、最小限表示される桁数。DWORD_MAXのとき、指定なしとして、既定値1となる。
215@param[in] field フィールド幅。
216@param[in] flags 書式フラグ。
217@param[in] signChar 符号部分の文字。\0なら存在しないとして扱われる。
218@return xの文字列表現
219*/
220Function FormatInteger(x As DWord, d As DWord, field As DWord, flags As FormatFlags, signChar As StrChar) As String
[335]221 '左揃えのときまたは精度が指定されているとき、ゼロフラグは無視される。
222 If (flags And Left) Or (d <> DWORD_MAX) Then
223 flags And= Not Zero
224 End If
225
226 If d = DWORD_MAX Then
227 d = 1
228 End If
229
230 Dim sb = New System.Text.StringBuilder
231 With sb
[355]232 If signChar <> 0 Then
233 .Append(signChar)
234 End If
235
236 Dim buf[MaxSizeU] As StrChar
237 Dim i = MaxSizeU
[335]238 While x <> 0
239 buf[i] = (x As Int64 Mod 10 + &h30) As StrChar 'Int64への型変換は#117対策
240 x \= 10
241 i--
242 Wend
243
[355]244 Dim len = (MaxSizeU - i) As Long
[335]245 If len < d Then
246 .Append(&h30 As StrChar, d - len)
247 End If
248
249 .Append(buf, i + 1, len)
250
[355]251 AdjustFieldWidth(sb, field, signChar <> 0, flags And (Not (Sign Or Blank)))
252 End With
253 FormatInteger = sb.ToString()
254End Function
255
256'! QWordの最大値18446744073709551615の文字数 - 1。FormatIntegerLU内で使用。
257Const MaxSizeLU = 19
258
259/*!
260@brief 文字列をフィールド幅まで満たされるように空白などを挿入する。
261@param [in,out] sb 対象文字列
262@param [in] field フィールド幅
263@param [in] hasSign 符号を持っている(負の値か)か否か
264@param [in] flags フラグ
265*/
266Sub AdjustFieldWidth(sb As System.Text.StringBuilder, field As DWord, hasSign As Boolean, flags As FormatFlags)
267 With sb
268 If .Length < field Then
269 Dim embeddedSize = field - .Length
[335]270 If flags And Left Then
271 .Append(&h20, embeddedSize)
272 Else
[355]273 Dim insPos As Long
274 If (flags And Zero) <> 0 Then
275 If ((flags And Blank) Or (flags And Sign) Or hasSign) Then
276 insPos++
277 End If
278 .Insert(insPos, String$(embeddedSize, "0"))
279 Else
280 .Insert(insPos, String$(embeddedSize, " "))
281 End If
[335]282 End If
283 End If
[355]284
[335]285 End With
[355]286End Sub
[335]287
288End Namespace 'Detail
289
290End Namespace 'Strings
291End Namespace 'ActiveBasic
Note: See TracBrowser for help on using the repository browser.