質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.93%

Schemeで関数に代入した値を使う方法

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 149

_syusyu_

score 1

Schemeで関数に代入した値を使う方法

lambda式で表される関数f(x)と2個の初期値を用いて、f(x)=0の根を探すプログラムを、二分法を利用して記述したいです。
プログラムの中で、f(x)に初期値を代入して得られる値を使いたいのですが、どう記述したら良いのかが分かりません。
初心者のため、他にも誤りがありましたら指摘して頂けると助かります。
Macbook AirでDr.racketを使用しています。

記述したプログラム

(define eps 1.e-10)
(define (enough x) (< x eps))
(define (middle x y) (/ (+ x y) 2))
(define (half-interval-method x0 x1 f)
  (let ((a (f x0))
        (b (f x1)))
    (cond ((and (or (and (< a 0) (< 0 b))
                   (and (< 0 a) (< b 0)))
               (enough (abs (- x0 x1)))) (middle x0 x1))
          ((enough (f (middle x0 x1))) (middle x0 x1))
          (else (half-interval-method (middle x0 x1) x1 f)))))

エラーメッセージ

application: not a procedure;
 expected a procedure that can be applied to arguments
  given: 2
  arguments...:

試したこと

set!も使ってみましたが、以下のエラーが出ました。

<: contract violation
  expected: real?
  given: #<void>
  argument position: 1st
  other arguments...:
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SaitoAtsushi

    2020/07/12 10:15

    質問中のエラーというのは書いたプログラムをどのように使ったときに出たエラーですか?

    キャンセル

回答 1

0

呼び出し方は

(half-interval-method 1.0 2.0 (lambda (x) (- (* x x x) (* 2 x) 3)))

といった要領で引数を与えればよく、特にエラーは生じないようです。

この手続きを呼び出すにあたって代入が発生する箇所はないので、何か根本的な思い違いをしているのではないかと思います。


また、 (手続きに与えられた名前から想像すると) 半分に区切った区間を (f x0) と (f x1) の結果次第でどちらを取るかを選択してそれを繰り返すことで範囲を狭めていくということをしたいのだと思いますが、条件の設定がデタラメなので意味のある繰り返しになっていません。

(and (< a 0) (< 0 b)) が成立する場合と (and (< 0 a) (< b 0)) が成立する場合で違う側の区間を選択するというのがアルゴリズムの根幹です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/12 19:17

    成程、私が色々と思い違いをしていたのですね。
    お答えを参考に、
    (else (half-interval-method (middle x0 x1) x1 f))
    の部分を、
    ((and (< a 0) (< 0 b)) (half-interval-method x0 a f))
    ((and (< 0 a) (< b 0)) (half-interval-method x1 b f))
    と書き直してみました。
    値が返ってくるようにはなりましたが、この記述は合っているのでしょうか?
    与える関数をsinにしたときに値が返って来ないので、間違っているのかも知れないとは思うのですが、本当に初心者なので、手探りで記述していて…すみません。
    誤っていたら教えて頂けると助かります。

    キャンセル

  • 2020/07/12 23:37

    関数 f はひとつの引数を受け取ってひとつの値を返すものですから、つまりは二次元座標に広がっています。
    つまり、 a や b は y 座標であり、 x0 や x1 は x 座標です。
    「区間」は関数の入力値 (つまりは x 座標) として与えられていますから、再起呼び出しをするにあたって y 座標が出現するのは変な話ですよね。
    そして区間を二つに分けてどちらかを選択することで範囲を狭めていかなければならないのに区間の中央が出てこないことを疑問に思いませんでしたか?
    端的に言えば間違っています。

    プログラムの書き方の話ではなくて、根を探すアルゴリズムの段階で理解できていないということでしょうか。
    理解できていないものは表現できないのも当たり前です。
    区間二分法 (単に二分法ということもあるようです) でウェブ検索すると図で説明したものも見つかりますので参考にするといいでしょう。

    Scheme の演習でもよく用いられるのでよく探せばそのものズバリの解 (Scheme で書かれたプログラム) も見つかるんですけどね……。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る