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
Line 
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
121 Dim e As Long, negative As Boolean
122 Dim s = FloatToChars(x, e, negative)
123
124 If negative Then
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
153 .Append(FormatIntegerD(e, 2, 0, Sign Or Zero))
154
155 AdjustFieldWidth(sb, field, negative, flags)
156 End With
157 FormatFloatE = sb.ToString()
158End Function
159
160'! DWordの最大値4294967295の文字数 - 1。FormatIntegerU内で使用。
161Const MaxSizeU = 9
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
174 FormatIntegerU = FormatInteger(x, d, field, flags, 0)
175End Function
176
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
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
232 If signChar <> 0 Then
233 .Append(signChar)
234 End If
235
236 Dim buf[MaxSizeU] As StrChar
237 Dim i = MaxSizeU
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
244 Dim len = (MaxSizeU - i) As Long
245 If len < d Then
246 .Append(&h30 As StrChar, d - len)
247 End If
248
249 .Append(buf, i + 1, len)
250
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
270 If flags And Left Then
271 .Append(&h20, embeddedSize)
272 Else
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
282 End If
283 End If
284
285 End With
286End Sub
287
288End Namespace 'Detail
289
290End Namespace 'Strings
291End Namespace 'ActiveBasic
Note: See TracBrowser for help on using the repository browser.