2010年1月23日
負の数を回避するのは案外簡単である。絶対値をとればいいのだ。
ただし、これでは符号の情報が失われてしまうので、「どこかにマイナスだった」という情報をとっておいて、
マイナスだった場合には=ROUND(・・・)の後に(-1)を掛ければいいのだ。地味に面倒だが、仕方ない。
だが、ここでさらに、もう1点、気付いてしまった。
0(ゼロ)もダメじゃん・・・
絶対値を取ろうが何をしようが、ゼロはゼロ。ゼロの対数はやはりExcelでエラーを返される。
ところで、有効数字2桁、3桁の「0」って幾らだろうか・・・。
悩んだ。大いに悩んだ。0.0、0.00にしようかとも思った。だが、これが有効数字かと言われるとやはり違う。
例えば、
0.0001
であったとしても
0.00010
0.000100
であり、決して
0.0
0.00
ではないからだ。
悩み抜いた挙句、「いいや、0のままで」という結論に達した。
つまり、ゼロのセルは空白セルや文字のセルと同じようにエスケープさせてあげればいいのだ。
何となく、色々と方法がありそうだが、正の数か負の数か、ゼロかゼロではないかの2つのBoolean変数を用意して
その時に応じてTrueとFalseを入れ替えてあげるという方法を取ることにした。
今までのスクリプトを何となく生かせそうだったので。
それぞれisMinusとisNotZeroという変数を宣言することにした。
何故isNotZeroでゼロでない場合をTrueにするかは、if文との関連であって、完全に趣味の世界。
perlだと「Unless」というのがあって、偽ならThen以降を実行というのがあるが、残念ながらこちらにはない・・・。
でもって、実際の制御だが、正の数か負の数かゼロかで3種類の分岐があることが分かるだろう。
if文を入れ子にしてもできるのだが、もう少し便利なものがあるので、そちらを使う事にした。
|
なんか、小難しい事が書いてあるが、if文のような分岐ではなく、3つ、4つ・・・と分岐を増やせるようだ。
これを使おう。
その他に、絶対値を使うので、数字を丸める部分の処理を、
c.Formula = "=ROUND(ABS(" & myCellFormula & "),1-INT(LOG10(ABS(" & myCellFormula & "))))"
に変更している。また、これに合わせて、significantCancelで、Leftで取り出して参照する文字列と、全部を書くと長くなってきたので、significantFigure2とsignificantCancelだけを書いておく。
Sub significantFigure2() Call significantCancel '重複防止の為、一度呼び出す '変数の定義 Dim myRange As Range Dim myCellFormula As String '式として変換する為の変数 Dim myCellValue As Variant 'variantで数字と文字列の判定 Dim startFrom As Variant 'variantで1文字目を取得 Dim isMinus As Boolean '負の数の判別用 Dim isNotZero As Boolean '0でないことの確認 Set myRange = Application.Selection For Each c In myRange.Cells '個々のセルを抽出 myCellFormula = c.Formula myCellValue = c.Value isNotZero = True If Len(myCellFormula) > 0 Then '空白セルをエスケープ If IsNumeric(myCellValue) Then '文字列セルをエスケープ '値が正か負か0かを判定。 'isMinusのBooleanに値を代入 Select Case myCellValue Case Is < 0 isMinus = True Case Is > 0 isMinus = False Case Is = 0 isNotZero = False End Select If isNotZero Then 'セルの先頭文字を取得して式か数かを判定。 '式なら=を除去 startFrom = Left(myCellFormula, 1) If startFrom = "=" Then myCellFormula = Mid(myCellFormula, 2) End If 'ここで丸めを実行 c.Formula = "=ROUND(ABS(" & myCellFormula & "),1-INT(LOG10(ABS(" & myCellFormula & "))))" '負の数の場合、マイナスを復活させる。 If isMinus Then c.Formula = c.Formula & "*(-1)" End If End If End If End If Next End Sub |
Sub significantCancel() '有効数字をキャンセル '変数の定義 Dim myRange As Range Dim myCellFormula As String Dim commaPosition '式中のコンマの位置。variant型 Set myRange = Application.Selection For Each c In myRange.Cells 'セルを抽出 myCellFormula = c.Formula If Left(myCellFormula, 11) = "=ROUND(ABS(" Then '=ROUND(ABS(以外のセルをエスケープ commaPosition = InStr(myCellFormula, ",") 'コンマの位置を取得 '=ROUND(ABS(を除いた12文字目からコンマ前までを取得 If IsNumeric(Mid(myCellFormula, 12, commaPosition - 13)) Then c.Value = Mid(myCellFormula, 12, commaPosition - 13) '数字であればそのまま代入 Else c.Formula = "=" & Mid(myCellFormula, 12, commaPosition - 13) '式であれば最初に=をつけて代入 End If End If Next End Sub |
ちょっと補足を。
For Eachの直後にisNotZero = Trueとしているのは、変数の初期化のようなもの。
仮に、直前に評価したセルがゼロで、isNotZero = Falseとなり、その値がそのままで次のセルの評価に
使われるのを避ける為に、セルを選びなおす度に初期値に戻すためのもの。
丸める部分の処理を丸ごとIf isNotZero Thenの中に入れ、ゼロのセルをエスケープするようにしている。
丸めた後にIf isMinus Thenで、負の数だった場合に、(-1)を掛けるという処理を追加している。
significantCancelの方は負の数関連の処理は全く追加していない。それは、もともとの数が、正だろうが負だろうが
そのままの形で丸める式に放り込んでいるからだ。絶対値を使っているので、式の中に入るのが負の数でも関係ないからだ。
その部分を抜き出してくるという処理なので、別に関係ないのだ。うん、よくできたプログラムだ。
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14]