エクセルVBAで上手く動かない?助けて下さい

このQ&Aのポイント
  • エクセルでVBAを使ってユーザー関数を作成しましたが、正常に動作しません。
  • 作成した関数は、INT関数を複数回連続で実行するものであり、特定の値が正しく計算されません。
  • 詳細なプログラムコードから問題箇所を見つけることが困難であり、アドバイスを求めています。
回答を見る
  • ベストアンサー

エクセルVBAで上手く動きません。

エクセルでVBAをつかって、ユーザー関数を作ったのですが、 うまく動きません。助けて下さい。 内容はINT関数が7回までしか連乗できないので、 何回でも掛けて切り捨てる関数を作りましたが・・・ プログラムは以下の通りです Function MULTINT(sdata1 As Single, ParamArray Optdata2()) As Long Dim i As Integer MULTINT = sdata1 For i = 0 To UBound(Optdata2()) MULTINT = Int(MULTINT * Optdata2(i)) Next i End Function 本来は、 MULTINT(84000,0.7)=58800 となって欲しいのですが、 MULTINT(84000,0.7)=58799 となってしまいます。どこがいけないのでしょうか? 困っています。助けて下さい。

質問者が選んだベストアンサー

  • ベストアンサー
  • TAGOSAKU7
  • ベストアンサー率65% (276/422)
回答No.2

なるほどわかりました。毎回切捨てなのですね。 ならばプログラミング的にはOKです。 なぜ58799になるかというと、Optdata2はDoubleの型を持つためにおきたものではないかと思います。 >MULTINT2 * Optdata2(i) 部分では、画面のデバッグ上では欲しい値になっているのですが、PCのメモリ内部では 58799.99999999999・・・ という値になったために、切り捨て直後の値は58800にならないものと思われます。 はっきり言ってINTのバグと言ってもいいですね。 なので、別の切り捨て関数を使用しましょう。 Function MULTINT(sdata1 As Single, ParamArray Optdata2()) As Long Dim i As Integer Dim lngWork As Long lngWork = Round(sdata1) For i = LBound(Optdata2) To UBound(Optdata2) lngWork = Round(lngWork * CSng(Optdata2(i))) Next i MULTINT = CLng(lngWork) End Function

kasaeru
質問者

お礼

親切にありがとうございます。が、残念ながらエクセル95なので Round関数が使えませんでした。(Roundは2000からみたいです) しかし、ご指摘のおかげで一度値を1000倍して、最後に1000分の1 する事で解決(?)できました。アリガト チュッ!(男です)

その他の回答 (1)

  • TAGOSAKU7
  • ベストアンサー率65% (276/422)
回答No.1

毎回INTをしない方が良いのでは? 返し値はLongなので、きちんとLongで返してあげましょう。 Function MULTINT(sdata1 As Single, ParamArray Optdata2()) As Long   Dim i    As Integer   Dim sngWork As Single   sngWork = sdata1   For i = LBound(Optdata2) To UBound(Optdata2)     sngWork = (sngWork * Optdata2(i))   Next i      MULTINT = CLng(sngWork) End Function

kasaeru
質問者

補足

すみません。質問の説明が不足でした。 A,B,C,D,E・・・・という不特定複数の 数値を掛け合わせて、「掛けるたびに切り捨て」というものが 作りたいのです。INTで説明すると =INT(INT(INT(INT(A*B)*C)*D)*E・・・) というものです。例えば MULTINT(2.5,2.5,2.5,2.5)=37 となってほしいのです。 INTでやると、7回までしか連続でできません。わがまま言ってすみませんが 助けてください。

関連するQ&A

  • Excel VBAにて2の100乗を計算するには

    プログラミングの勉強でVBAを学んでいるものです 以下の様な問題を出されました 2の100乗の値を計算する。この値はLong型で表せる最大の値をはるかに超すので、十分な大きさのInteger型の配列を用意し、その各要素で各けたの値を表す。値を2倍するサブプロシージャ「二倍」を書いてプログラムを完成させ、値を計算せよ。 Option Explicit Sub 二の百乗() Const n As Integer = 200 Dim s(n) As Integer Dim i As Integer, j As Integer s(1) = 1 For i = 2 To UBound(s) 'UBoundは配列の最大の添え字を返す関数 s(i) = 0 Next i For i = 1 To 100 二倍 s Next i For i = UBound(s) To 1 Step -1 If s(i) <> 0 Then Exit For Next i For j = 1 To i Cells(1, j).Value = s(i - j + 1) Next j End Sub セル一つに計算結果を表示させられないことはよく分かるのですが、そのための2の掛け算を全く思いつきません 二倍のサブプロシージャをどのようにすればいいのでしょうか

  • Excel VBAライフゲーム

    ExcelのVBAでライフゲームを作りたいのですが、次のプログラムの途中以降がわかりません。 もしよろしければ、このつづきの簡単な実行できるVBAライフゲームを教えてください。 続きのプログラムを教えていただけたら幸いです。 Option Explicit Const ALIVE As Integer = 1 Const DEAD As Integer = 0 Const SIZE As Integer = 19 Const Tmax As Integer = 100 Dim C(SIZE, SIZE) As Integer Sub LifeGame() Dim InitRate As Single Dim T As Integer Dim N As Integer Dim Cnext(SIZE, SIZE) As Integer Dim I As Integer, J As Integer InitRate = -1 Do While InitRate < 0 Or 1 < InitRate Loop For I = 0 To SIZE For J = 0 To SIZE If Rnd() < InitRate Then C(I, J) = ALIVE Else C(I, J) = DEAD End If Next J Next I For T = 1 To Tmax For I = 0 To SIZE For J = 0 To SIZE If C(I, J) = ALIVE Then Cells(I + 1, J + 1).Value = "■" Else Cells(I + 1, J + 1).Vallue = "" End If Next J Next I For I = 0 To SIZE For J = 0 To SIZE N = Count(I, J) Next J Next I For I = 0 To SIZE For J = 0 To SIZE C(I, J) = Cnext(I, J) Next J Next I Next T End Sub Function Count(I As Integer, J As Integer) As Integer End Function

  • Excel VBAで別ブックのマクロから配列を取る

    Excel VBAで別ブックのマクロで計算した結果を配列で渡したいのですが、上手い方法が見つかりません。 同じブック内であれば、 Function GetAry(Imax As Integer, ByRef MyAry As Variant) as Boolean のような関数を作れば、GetAry = True の時に返値の MyAry が有効であるという判断ができますが、この関数を別ブックから使う場合は、参照渡しができません。 これはVBAの仕様なので仕方ないとして、以下のようなマクロを組んでみました。 '------------------------------------------------------- ' Book1.xlsm(呼び出される側) '------------------------------------------------------- Function MyAry(Imax As Integer) As Variant Dim i As Integer Dim SubAry() As Variant If Imax > 10 Then MyAry = False Else For i = 1 To Imax ReDim Preserve SubAry(i) SubAry(i) = i Next MyAry = SubAry End If End Function '------------------------------------------------------- ' Book2.xlsm(呼び出す側) '------------------------------------------------------- Sub GetMyAry() Dim DataAry As Variant Dim Imax As Integer Imax = 11 DataAry = Application.Run("Book1!MyAry", Imax) If DataAry <> False Then MsgBox UBound(DataAry) Else MsgBox DataAry End If End Sub '------------------------------------------------------- Imax = 11 であれば、メッセージボックスに False が表示されますが、Imax = 10 だと当然ですが「型が一致しません」というエラーになります。 エラートラップで誤魔化そうかとも思ったのですが、もっとスマートな方法がないでしょうか。 よろしくお願いします。

  • エクセル VBA 変数を一括で宣言したい

    こんにちは。VBAプログラム初心者です。 変数を宣言する際、 dim オーダ番号 as long, オーダ番号2 as long, …オーダ番号100 as long という内容を一括で宣言することは可能でしょうか? イメージ的には下のような感じなのですが。。。 dim i as integer for i = 1 to 100 dim オーダ番号i as long dim 単価i as long next マクロで便利にするつもりが余計面倒になっていて困っております。 解決策を教えていただけましたら幸いです。 何卒よろしくお願いいたします。

  • EXCEL VBA 配列変数の値すべてを返すには

    EXCELは2002ですが、97でも動くと嬉しいです。 《質問》 1~10をランダムに並べるためのプログラムを書きました。 これはこれで動くのですが、一行(3行目)だではなく 4行目にも、5行目にも同じことをしたい場合、 バブルソートの部分をサブルーチン(関数)にしたいのですが X_v() = GetSortArray(n_s,n_v)()とはできません。.cloneもだめですよね。 かといって、要素毎に引くとその度にRndが効いて、1~10が並びません。 どのようにやるのが、スマートなのでしょうか?よろしくお願いします。 《以下プログラム》 Sub Bu_Click() Dim i As Integer Dim j As Integer Const n_e = 10 Const n_s = 1 Dim X_r(n_e) As Long Dim X_v(n_e) As Long Dim temp1 As Long Dim temp2 As Integer Randomize For i = n_s To n_e X_r(i) = Int(Rnd * 10 ^ 9) X_v(i) = i Next i For i = n_s To n_e - 1 For j = n_s To n_e - 1 If X_r(j + 1) < X_r(j) Then temp1 = X_r(j + 1) X_r(j + 1) = X_r(j) X_r(j) = temp1 temp2 = X_v(j + 1) X_v(j + 1) = X_v(j) X_v(j) = temp2 End If Next j Next i For i = 0 To n_e - 1 Cells(3, 3 + i).Value = X_v(i + 1) Next i End Sub Public Function GetSortArray(s As Integer, e As Integer) As Long() Dim r() As Long Dim v() As Long Dim temp1 As Long Dim temp2 As Integer ReDim r(e) ReDim v(e) Randomize For i = s To e r(i) = Int(Rnd * 10 ^ 9) v(i) = i Next i For i = s To e - 1 For j = s To e - 1 If r(j + 1) < r(j) Then temp1 = r(j + 1) r(j + 1) = r(j) r(j) = temp1 temp2 = v(j + 1) v(j + 1) = v(j) v(j) = temp2 End If Next j Next i GetSortArray = v() End Function ありゃ?Tabのスペース消えますね。

  • VBAについて教えてください。

    職場のエクセルのVBAを見ていたら、下記のように書かれていました。VBAを勉強し始めたばかりで何が書かれているのか解りません。 お手数ですが教えてください。よろしくお願いします。 Function F_Crypt(Data As Long, Seed As String) As Long Dim i As Long, j As Integer, act1 As Long, act2 As Long, iSeed As String If Len(Seed) > 3 Then j = 3 Else j = Len(Seed)

  • エクセルVBAで2つの画像を比較したい

    こんにちは。VBAの初心者です。 エクセル2003のVBAを使って、シートに読み込んだ縦横24ピクセルの2つの画像(picA、picB)を比較したいと考えています。VBなどのページを参考に、APIのGetPixel関数を使えばなんとかなりそうだというところまではたどり着いて、以下のコードを組んでみたのですが、うまく動きません。 Private Declare Function GetPixel Lib "gdi32" _ (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long Private Sub CommandButton1_Click() Dim picA As Image Dim picB As Image Dim p1 As Integer Dim p2 As Integer Dim ScreenhDC As Long For x = 1 To 24 For y = 1 To 24 p1 = picA.GetPixel(ScreenhDC, x, y) p2 = picB.GetPixel(ScreenhDC, x, y) If p1 <> p2 Then MsgBox "違う画像です" Exit Sub End If Next Next MsgBox "同じ画像です" End Sub 「p1 = picA.GetPixel(ScreenhDC, x, y)」のところで「実行時エラー'91': オブジェクト変数またはWithブロック変数が設定されていません。」というメッセージが出て止まってしまいます。解決法をご教示いただけませんでしょうか。 そもそもエクセルのVBAではAPIは使えないなどということはありますか?

  • VBAの変数変換のことです

    VBAの変数変換のことです 整数変数=実数変数や実数変数=整数変数でCIntやCSng関数を使わないでOKでしょうか? Dim VAR(20) As Single '単精度浮動小数点数型 (Single) Dim IVARO(20) As Integer '整数型 (Integer) Dim IVAROC(20) As Integer '整数型 (Integer) IVARO(NCD) = VAR(NCD) 'Single to Integer IVAROC(NCD) = CInt(VAR(NCD)) 'Single to Integer これで、IVARO(NCD)とIVAROC(NCD)には同じ値が入っているのですが、 整数=実数でCInt関数を使わないで整数にする構文はOKでしょうか?

  • Excel VBA ParamArray 可変個引数の渡し方

    Excel VBAで 可変個引数関数Fanc1から、その引数を 可変個引数関数Fanc2に渡したい。 下記例では、A1=a, B1=b, C1=cのとき、#VALUE!となります。  Concatenate2(A1:B1,C1,"po")="abcpo" 問題無し  Fanc1(A1:B1,C1,"po")=#VALUE! Fanc1でも上と同じ出力にしたいのです。 Function Concatenate2(ParamArray MyArray()) As String Dim S As String Dim v As Variant Dim c As Variant For Each v In MyArray If TypeName(v) = "Range" Then For Each c In v S = S & c.Value Next Else S = S & v End If Next Concatenate2 = S End Function Function Fanc1(ParamArray MyArray()) As String Fanc1 = Concatenate2(MyArray()) End Function

  • Excel VBA配列をFunctionに渡す

    こんばんは、引数について教えてください。 Excel VBAの関数を作っていましたが、 1.Function ColumnArrayの部分でコンパイルエラーが発生し、  「配列がありません」と表示されます。  引数を配列のみで渡した場合、問題なく渡せるようですが、  他の引数と、CriteriaArrsの配列と一緒に渡せないのでしょうか。  すべて配列として1つにまとめて渡さなければならないのでしょうか。 2.CriteriaArrs = Array("田中", "鈴木")の部分は、文字列の増減が発生しますので  配列はParamArray  CriteriaArrs()とした方がよいのでしょうか 説明が不足している点があるかもしれませんが宜しくお願いいたします。 Function ColumnArray(SheetName As Worksheet, _ StartCell As Range, _ FieldColumn As Long, _ CountColumn As Long, _ CriteriaArrs As Variant _ ) As Long ・・・ End Function ------------------------------------- sub test() Dim CriteriaArrs() As Variant Dim SheetA As WorkSheet DIm RangeA range CriteriaArrs = Array("田中", "鈴木") set SheetA =Worksheet(1) set RangeA=Range("B3") FilterCount = ColumnArray(SheetA, RangeA, 3, 2, CriteriaArrs) end sub

専門家に質問してみよう