こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

数値+演算子+数値を計算したい!

数値1+演算子+数値2を計算させたいのですが、1 + 1 のような計算を格納するにはどうしたらいいですか?


数値1 Decimal
数値2 Decimal
演算子 String
結果  Decimal

Decimal = Decimal + String + Decimal だとエラーが出ます。当たり前ですけど・・・

投稿日時 - 2009-06-13 13:27:16

QNo.5040294

困ってます

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

> Eval関数を使って、文字列を渡すと自動計算して結果も何もかもStringで扱いたいと思っています。
> Stringは20億桁ほど扱えるんですよね・・・Decimalより扱える桁が多そうな気がして・・・素人考えですみません。

20億桁を記憶することが出来ても、それで計算することは出来ません。プログラムどうこうというより、コンピュータの構造上不可能です。

DecimalやIntegerなどが扱うのは「数値」、
String型が扱うのは「数字」です。

「数値」は計算することはできますが「数字」は計算できません。

数値とは
12345 が 1万2千3百4十5 という分量です。
一方、数字とは
12345 が「いち」「に」「さん」「よん」「ご」という文字の羅列であり、「数値」を表すための「文字」を並べたものにすぎません。

計算を全てString型でやるということは、不可能ではありませんが非常に効率が低下します。(個人的にはDecimalもNGなんですけども)


あと、Option StrictはOnにしたほうがいいです。今回のケースであれば、Offにする必要はありません。

参照設定でMicrosoft Script Control 1.0が見つからなかったのは、
「COM」タブから探していないからでしょう。
「参照の追加」を開くと[.NET][COM][プロジェクト]・・・とあるはずなので、[COM]を選択し、「Microsoft Script Control 1.0」を探して追加してください。
さらに、コードの次の部分を書き換えます。

[ ScriptControlクラスの作成箇所 ]
Dim js As Object
js = CreateObject("ScriptControl")
  ↓
Dim js As New MSScriptControl.ScriptControl

[ Eval関数の呼び出し箇所 ]
Total = js.Eval(Work) '遅延バインディングを使用できません
  ↓
Total = js.Eval(Work).ToString()

これで遅延バインディング及び暗黙的型変換は発生しなくなるはずです。

投稿日時 - 2009-06-15 07:11:15

お礼

ありがとうございます。

薄々なんかおかしいと思ってましたが、なるほど数値と数字って違うんですね。
分量と文字・・・為になります。

Option Strict Onに戻しました。

COMの使い方がわかりません。
プロジェクト設定で参照を追加できましたが、コードのインポートの仕方がわかりません。

Imports Microsoft JScript Control 1.0 なわけないですし・・
名前空間すらないし・・・

プロジェクト設定で参照を追加すると、Importsを書かなくても実行できます。
'Imports Microsoft.JScript とコメントアウトさせてます。
これは問題ですか?

質問1.
参照を追加するとインポート文は不要ですか?

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

Dim js As New MSScriptControl.ScriptControlにすると、Total = js.Eval(Work)だけでも遅延バインディングがなくなりました。

MSScriptControl.ScriptControlを検索するとまったくヒットしません。
使い方がヘタなのかもしれません。
実際ヘタだからヒットしてないんですけど。

MSScriptControl.ScriptControlを検索するのに、ヘルプ> カテゴリから検索・検索・目次・キーワード といろいろありますが、
どれで検索しますか?

自分は、

ヘルプ>検索
言語:Visual Basic
テクノロジ:.NET Compact Framework .NET開発 Visual Basic 2005 Windows Vista
コンテンツの種類:すべて

フィルタ条件:.NET Framework
検索する文字列:MSScriptControl.ScriptControl

ヒットしません。

言語:Visual Basic テクノロジ以下すべて:すべて
検索する文字列:MSScript

ヒットしません。

MSScriptControl.ScriptControlってなんですかーーーーーー状態です。

質問2.
ライブラリの検索方法を教えてください。

投稿日時 - 2009-06-16 17:36:52

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(11)

ANo.11

>質問3.
>DecimalがNGの理由を教えてください。できるだけ簡単に・・・

 まず最初に、msdnから、decimal型の説明を載せておきますね。
http://msdn.microsoft.com/ja-jp/library/xtba3z33(VS.80).aspx

 ここに書いてある、「すべての数値型の中で最もパフォーマンスの低いデータ型です。」というのが、おそらく総ての理由です。
 この型の本当の存在意義を知るためには、そもそも、2進数と10進数での演算時の誤差に関する知識が必要です。
 単純化して簡単に言うと、10進ではちゃんと割り切れる計算式でも2進数で計算すると割りきれない、又は、その逆のパターンが数多く存在します。そのため、2進数で計算する時と10進数で計算する時では、誤差の出方が変わります。
 普通ならば、こんな誤差は、気になりません。でも、気になる人もいます。たとえ、20桁の莫大な大きさの数値でも、単位が円や$なら、ピタ1たりとも計算値は狂ってはいけないですよね。銀行業務で、「1円くらいだから別にいいよね。金庫にはうん千億のお金あるし・・・」なんて言ったら即クビです(笑)
 こういう時のために、decimal型と言うのは存在します。

 普通、コンピュータで計算する時には、2進数で総ての演算を行います。コンピュータは、ご存じの通り2進数で総ての処理を行いますから、計算も2進数でやるのが一番効率がいいんです。もちろん、数値の保管も2進数で行います。それが一番効率がよいですから。入力の数値を2進数に変換し、総ての処理を2進数で行い、最後に表示する時に、もう一度10進数に戻しているわけです。
 でも、2進数と10進数での計算結果が違うことが困ると言われたら、10進で計算せざるをえません。decimal型での演算は基本的に10進で行います。数値の格納も10進で行います。コンピュータに無理を言って10進で演算させるわけですから、もちろん効率はだだ落ちです。でも、計算を総て10進で行うので、紙と鉛筆で計算した時と結果はぴったり同じになります。(ものすごく、話を単純化しています。実際の処理も理論もかなり複雑です。)
 これが、冒頭の「すべての数値型の中で最もパフォーマンスの低いデータ型です。」につながります。
 たいていの参考書や、ソフトでdoubleで計算するのは、このためです。というより、必要がなければ、decimalは使わない物と思っても良いです。

 誤解を招きかねない表現が少々ありますが、出来るだけ簡単に言うとこんな感じです。

投稿日時 - 2009-06-21 23:07:45

お礼

ありがとうございます。

パソコンのCPUがトリプルやクワッドの時代なので、過度なマシンパワーの消費を気にするのは必要はないと思っています。

無限ループとかあきらかに、マシンが急激に重くならないなら大した問題ではないとも考えています。
自分のプログラムには寛容です。

VS2005の起動の遅さ、Windowsのヘルプの遅さに耐えているので、
動いてるか止まってるかわからない状態になるプログラムでない限り他人のプログラムに対しても寛容です。


>数値を2進数に変換し、総ての処理を2進数で行い、最後に表示する時に、もう一度10進数に戻しているわけです

decimalの遅さはわかりました。

コンピューターはすべてを2進数で扱いたいのですね。
2進数を10進数で表示するので、小数点で誤差が出るわけですね。なるほど。

投稿日時 - 2009-06-23 01:47:48

ANo.10

> COMの使い方がわかりません。
> プロジェクト設定で参照を追加できましたが、コードのインポートの仕方がわかりません。

COMも.NETのクラスとほぼ同じように扱うことが出来ます。

> プロジェクト設定で参照を追加すると、Importsを書かなくても実行できます。
> 'Imports Microsoft.JScript とコメントアウトさせてます。
> これは問題ですか?

問題ありません。
Importsは、名前空間の指定を省略するためのものにすぎません。

> 質問1.
> 参照を追加するとインポート文は不要ですか?

絶対必要なものではありません。上記にあるとおり、名前空間の指定を省略するためのものです。

名前空間の省略、とは例えば
Dim AAA As System.String
と書かなければならないところを、Imports Systemとすることで
Dim AAA As String
と省略することができます。
※「System」をはじめいくつかの名前空間は既定でImports状態になっています。


> 質問2.
> ライブラリの検索方法を教えてください。

.NET Framework標準及びVisual Studio以外のライブラリやCOMクラスに関してはMSDNに掲載されていないものがほとんどです。
名前空間やクラス名などは、参照設定で追加したあとに「表示」メニューにある「オブジェクトブラウザ」を使えば調べることが出来ます。

投稿日時 - 2009-06-17 17:23:43

お礼

ありがとうございます。

名前空間を省略しない場合は、Imports文が不要ということは本に書いていました。
思い出しました。
この場合省略していないので、Imports文がなくてもエラーが出ないだけだったのですね。

なるほど。「表示」メニューにある「オブジェクトブラウザ」を使うのですね。
使ってみます。

MSScriptControl.ScriptControlは、Microsoft JScript Control 1.0を参照しており、
Microsoft.JScriptは一切参照していないのでプロジェクト設定の参照から削除しました。

継承メンバの表示にチェックを入れたら、Eval(String) As Objectが表示されました。
感動です。

ありがとうございましたmm

投稿日時 - 2009-06-18 19:35:58

ANo.9

こんにちは、

NET以降だと、Eval関数について、以下の様なページを見つけました。

参考までに

http://dobon.net/vb/dotnet/programing/eval.html

投稿日時 - 2009-06-15 09:11:51

お礼

ありがとうございます。

そのサイト知ってます。
Microsoft.JScriptがなんなのかわからなかったので、いまもわかってないですけど・・・参考にしませんでした。
しませんでしたではなく・・・できなかったと言った方が正解です。

>計算を全てString型でやるということは、不可能ではありませんが非常に効率が低下します。(個人的にはDecimalもNGなんですけども)

最後の括弧が気になります。
気になり出すと、余計に気になります。

(個人的にはDecimalもNGなんですけども)・・・・・・なぜDecimalがダメなんですか・・・

確かにDouble型で計算しているコードが多いです。

質問3.
DecimalがNGの理由を教えてください。できるだけ簡単に・・・

投稿日時 - 2009-06-16 17:39:24

ANo.7

追伸です。

お礼のプログラムよく見ないで、返事をしましたが。
このプログラム、なんか、変じゃない??

関係のないところは、省略したのですか??

私の勘違いかな??

投稿日時 - 2009-06-14 19:29:24

補足

電卓ソースです。
例外・エラー処理はまだです。

'Imports Microsoft.JScript

Public Class Form1

Dim Total As String = "0"
Dim Input As String = ""
Dim Calc As String = "+"
Dim Flag As String = "演算子" '演算子 or 数値

Sub Value(ByVal Data As String)
Dim Work As String = ""

Flag = "数値"
Input = Input + Data
TextBox1.Text = Input
End Sub

Sub Calclate(ByVal Data As String)
Dim Work As String = ""

Dim js As Object
js = CreateObject("ScriptControl")
js.Language = "JScript" '遅延バインディングを使用できません

If (Flag = "数値") Then
Flag = "演算子"
Work = Total + Calc + Input
Total = js.Eval(Work) '遅延バインディングを使用できません
Input = ""
TextBox1.Text = Total
End If

If (Data = "=") Then
Total = "0"
Calc = "+"
Else
Calc = Data
End If
End Sub

Sub C()
Total = "0"
Calc = "+"
Input = ""
TextBox1.Text = Total
End Sub

Private Sub ButtonNum0_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonNum0.Click
Call Value("0")
End Sub

・・・
省略
ボタン1つ1つに呼び出し関数を書いてます。

オブジェクト指向にほど遠い・・・

投稿日時 - 2009-06-15 01:17:28

お礼

ありがとうございます。
確かに、ご指摘の通り、実行するとデバッグ中にプロセスが強制的に落ちます・・

数値1ボタンを押すと01と表示されたので、嫌な予感がしましたが、
演算ボタンを押すと落ちます・・・

トータルの初期値が0なので、当たり前のように01と表示されます。

深夜1:14分・・ついに完成しました!

電卓完成の1歩手前です。(この状態で動くことは動きます)

あとはゼロ除算の例外処理をどこに書くのか悩む段階に来ました。

初めての例外・エラー処理・・・

疲れたので寝ます。

投稿日時 - 2009-06-15 01:16:22

ANo.6

追伸、

こちらは、

Microsoft Visual Basic 2008

で、書いています。

そちらも環境を書くようにしましょう。

投稿日時 - 2009-06-14 19:06:58

お礼

ありがとうございます。

こちらは、Microsoft Visual Basic 2005です。

投稿日時 - 2009-06-15 01:04:20

ANo.5

こんばんは、
もしなければ、ないで、流石にエクセルは、もっているでしょうから。
エクセルの方を使った場合を、載せておきます。


Dim app As Object

app = CreateObject("Excel.Application")

Dim s As String

s = "1+1+1+2-1*3"

Debug.WriteLine(app.Evaluate(s))

app.Quit()

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(app)

app = Nothing

計算結果 2

投稿日時 - 2009-06-14 19:01:39

お礼

ありがとうございます。

エクセルではなく、ソフトが作りたいのですmm

投稿日時 - 2009-06-15 01:03:22

ANo.4

こんにちは、環境がわからないのですが。

参照設定で、

Microsoft Script Control 1.0

は、存在しますか??

なかったら、エクセルのEvaluate()を使うのも一つの手です。

投稿日時 - 2009-06-14 18:39:47

お礼

ありがとうございます。
Visual Studio 2005のVisual Basicで作ってます。

その参照設定ウィンドウが見つからなかったです。
プロジェクト設定に参照という項目があり、そこに参照の追加というのがありました。
Microsoft.JScript 8.0.0.0 v2.0.50727というのがあったので参照を追加しました。

初めて参照を追加しました・・・

Imports Microsoft.JScriptを記載してもエラーがなくなりました。
プロジェクトに参照の追加をしているので、Imports要らないみたいです・・・

「Option Strict Onでは、遅延バインディングを使用できません。」

これは、処理が遅い関数に投げると警告が出ます。
プロジェクト設定でOption Strict Onをオフにすれば、コンパイルできますが、ダメダメプログラムという烙印が付きます。

諦めて、Option Strict Onをオフにします・・・

ボタンを押したら呼び出される関数だけ書いてます。

・・・そのソースぼろぼろでした・・・動くやつ貼ります。

投稿日時 - 2009-06-15 01:01:09

ANo.3

こんにちは、VBなのか、VBAなのか、よく解りませんが。
どちらでも、以下のコードは、実行できますよ。
ただし、たぶん、十進計算では、ないです。


Dim js As Object

js = CreateObject("ScriptControl")
js.Language = "JScript"

Dim s As String
Dim data As Integer

data = 10

s = "2 + 1 + 1" & "+" & data

Debug.Print(js.Eval(s))


計算結果 14

VBAなら、Evalに変わる、関数があるみたいです。

投稿日時 - 2009-06-13 18:54:55

お礼

遅延バインディングの回避方法を教えてください・・・
自力では無理です・・・

Public Class Form1

Dim Total As String = "0"
Dim Input As String = "0"
Dim Calc As String = "+"
Dim Flag As String = "演算子" '演算子 or 数値

Sub Value(ByVal Data As String)
Dim Work As String = ""

Flag = "数値"
Input = Input + Data
TextBox1.Text = Input
End Sub

Sub Calclate(ByVal Data As String)
Dim Work As String = ""

Dim js As Object
js = CreateObject("ScriptControl")
js.Language = "JScript" '遅延バインディングを使用できません

If (Flag = "数値") Then
Flag = "演算子"
Work = Total + Calc + Input
Total = js.Eval(Work) '遅延バインディングを使用できません
Input = ""
TextBox1.Text = Total
End If

If (Data = "=") Then
Total = "0"
Calc = "+"
Input = ""
TextBox1.Text = Total
End If

End Sub

End Class

投稿日時 - 2009-06-14 16:10:05

ANo.2

すでに的確な回答が出ていますので、少し違う視点からアドバイスを。

2つの値(Value1とValue2)を加算した結果(Answer)を得るには
Dim Value1 As Decimal = 1
Dim Value2 As Decimal = 1
Dim Answer As Decimal
Answer = Value1 + Value2
とすればよい、というのは分かると思います。

次のステップとして、演算子「+」を文字列で指定することで、演算子を動的に変化させ、減算・乗算・除算などを行えるようにしたいのだと受け取りました。

しかし、文字列を演算子として扱うことはおっしゃるとおり出来ません。
ではどうするか。
「演算子の文字列」に代入されるであろう演算記号全てのケースに対し、分岐処理を作っておけばよいのです。すなわち
・文字列が「+」だったら加算する
・文字列が「-」だったら減算する
・文字列が「*」だったら乗算する
・文字列が「/」だったら除算する
と、このように演算子文字列にあわせて想定されるパターンをプログラミングします。

Dim Value1 As Decimal = 1
Dim Value2 As Decimal = 1
Dim Operate As String = "+" ' 演算子を示す文字列
Dim Answer As Decimal

' 文字列が「+」だったら加算する
If Operate = "+" Then
Answer = Value1 + Value2
End If

' 文字列が「-」だったら減算する
If Operate = "-" Then
Answer = Value1 - Value2
End If

' 文字列が「*」だったら乗算する
If ・・・・

この先はご自分で考えてみてください。


※提示したコードは、あくまで考え方を理解しやすいように書いています。実際には分岐処理をSelect Caseにし、演算子文字列が + - * / 以外の場合にどう対処するか、という点も考慮する必要があります。

投稿日時 - 2009-06-13 17:04:21

お礼

ありがとうございます。

「Decimal + String + Decimal」では計算できないため、Stringごとにcase文でDecimal (+, -, *, /)に振り分けるのですね。

Decimal + Decimal
Decimal - Decimal
Decimal * Decimal
Decimal / Decimal

なるほど。

Stringに1つに固めてString + String + Stringで一気に計算しようとがんばってみました。
エラー出てますけど・・

Eval関数を使って、文字列を渡すと自動計算して結果も何もかもStringで扱いたいと思っています。

Stringは20億桁ほど扱えるんですよね・・・Decimalより扱える桁が多そうな気がして・・・素人考えですみません。

投稿日時 - 2009-06-15 00:03:10

ANo.1

Stringを判定して場合わけじゃダメ?

投稿日時 - 2009-06-13 14:25:00

お礼

ありがとうございます。

「Decimal + String + Decimal」では計算できないため、Stringごとにcase文でDecimal (+, -, *, /)に振り分けるのですね。

Decimal + Decimal
Decimal - Decimal
Decimal * Decimal
Decimal / Decimal

なるほど。

Stringに1つに固めてString + String + Stringで一気に計算しようとがんばってみました。
エラー出てますけど・・

Eval関数を使って、文字列を渡すと自動計算して結果も何もかもStringで扱いたいと思っています。

Stringは20億桁ほど扱えるんですよね・・・Decimalより扱える桁が多そうな気がして・・・素人考えですみません。

投稿日時 - 2009-06-15 00:02:48

あなたにオススメの質問