Languages/Ruby or Rails2008/08/01 13:36

이 문제는 나그네 님께서 지적해주신 문제입니다. 최신 버전의 Rails는 일반 html 파일에 포함된 form의 input 필드들과 연동할때, 약간의 문제가 있습니다.

가령 Beginning Ruby on rails의 5장에 수록된 예제처럼 input.html 파일을 다음과 같이 만들었다고 해 봅시다.

<html>
<body>
    <form action="/look/at">
    <input type="text" name="text1"/>
    <input type="submit"/>
    </form>
</body>
</html>

이 form에 뭔가를 입력하고 submit 버튼을 누르면 /look/at 액션이 실행될 것이고, 그 결과가 화면에 출력될 것입니다. 그런데 그냥 이렇게만 하면 별 문제가 없다가, 위의 html 코드를 다음과 같이 바꾸면 문제가 발생합니다.

<html>
<body>
    <form action="/look/at" method="post">
    <input type="text" name="text1"/>
    <input type="submit"/>
    </form>
</body>
</html>

위와 같이 바꿔놓고 submit  버튼을 눌러보면, 다음과 같은 오류가 발생하는 것을 볼 수 있습니다.

ActionController::InvalidAuthenticityToken in LookController#at

액션 컨트롤러 쪽에서 AuthenticityToken이라는 것을 요구하는데 그게 없기 때문에 발생하는 오류입니다. 이 문제를 좀 더 정확하게 이해하기 위해, 다음과 같이 해 봅시다. 일단 controller Look에 input이라는 액션을 추가합니다.

class LookController < ApplicationController
    def at
        @data = params[:text1]
    end

    def input
    end

end

그런 다음 위의 html 코드를 다음과 같이 바꾸고, app/views/look 아래에 input.html.erb 라는 이름으로 복사해 넣습니다.

<html>
<body>
    <% form_tag '/look/at', :method=>:post do %>
    <input type="text" name="text1"/>
    <input type="submit"/>
    <% end %>
</body>
</html>

그런 다음에, 브라우저로 /look/input을 엽니다. 그리고 나서 브라우저의 소스 코드 보기 기능을 통해 소스 코드를 봅시다. 다음과 같이 되어 있는 것을 볼 수 있습니다.

<html>
<body>
 <form action="/look/at" method="post"><div style="margin:0;padding:0"><input name="authenticity_token" type="hidden" value="8f846ee3232eda791b4bf4c9d6d0a20478afcf8a" /></div>
 <input type="text" name="text1"/>
 <input type="submit"/>
 </form>
</body>
</html>

결국, /look/at은 method가 post일때 위의 token이 오기를 기대하는데 안오니까 불평을 해 댔던 것이죠. 이 문제를 해결하는 방법은 두가지가 있는데, 위에서처럼 모든 form 태그를 전부 form_tag 메소드를 써서 생성하는 것입니다. 그러면 알아서 넣어주니까 괜찮죠.

하지만 <div> 태그가 원래 원칙적으로 line break를 유발하는 습성이 있기 때문에, 웹 디자이너에게는 솔직히 짜증나는 부분이 될 수 있습니다. 그냥 hidden input filed로 두면 되었을텐데 div는 뭐하러 두었는지 참 ㅋㅋ

가장 간단한 해결책은 CSRF(Cross-Site Request Forgery) 공격을 막기 위해 도입된 위 feature를 강제로 동작하지 않도록 만드는 것입니다.

위의 경우라면, 컨트롤러 Look에 다음의 한줄을 넣어주세요.

skip_before_filter :verify_authenticity_token

제가 Beginning Ruby on Rails를 번역하면서 원저자가 책을 썼던 시점에 비해 바뀐 부분을 반영해 넣느라 고민을 좀 했었는데, 이렇게 책을 내놓고 보니 또 그 와중에 뭔가 새로운 기능이 계속 추가가 되어서 -_-;;

어쨌던 불편을 끼쳐드려서 죄송합니다. 앞으로도 이런 부분을 발견할 때 마다, 그리고 독자 분들의 질문이 있을 때 마다 가능한한 열심히 답변을 드리도록 하겠습니다.




Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/148 관련글 쓰기

댓글을 달아 주세요

  1. 전 원인도 모르고 그냥 첫번째 방법 썼는데 ^^ 좋은 정보 감사합니다~

    2008/08/01 14:26 [ ADDR : EDIT/ DEL : REPLY ]

Languages/Ruby or Rails2008/07/17 14:47

passenger를 설치하는 절차는 우선 다음의 명령을 입력하는 것으로 시작된다.

sudo gem install passenger

엔간하면 이 절차는 정상적으로 완료될 것. 하지만 그 다음이 문제. 설치 문서에는 passenger-install-apache2-module 을 실행하라고 나오는데, 이 파일은 /var/lib/gems/1.8/gems/passenger-2.0.2/bin 디렉터리 아래에 있는데다, 결정적으로 실행 권한이 설정되어 있지 않다.

그러므로 실행하려면 그 디렉터리 아래에 가서, sudo ruby passenger-install-apache2-module 처럼 실행해 주어야 한다. 그런데 그렇게 실행해 보면, rake가 gems 디렉터리 아래에 분명 설치되어 있는데도 설치되어 있지 않다고 불평하는 일이 발생한다. (이런...)

이런 일이 발생했다면, 여러분의 gems installation에 뭔가 문제가 발생한 것이다. -_-;
http://agileweb.wordpress.com/2008/07/18/how-to-install-rails-21-on-ubuntu-in-5-steps/
위의 링크를 참조해서 여러분의 gems installation 자체를 업데이트해보는 것이 좋겠다. 그런 다음 rails, passenger 등등을 다시 설치해야 한다.

이것은 rake 실행파일이 /usr/bin/ 아래에 복사되어 있지 않기 때문에 발생하는 문제. 따라서 sudo cp /var/lib/gems/1.8/gems/rake-0.8.1/bin/rake /usr/bin 과 같이 해주어야 한다. 그러면 문제가 해결된다. (카피가 찜찜한 분은 심볼릭 링크를 걸어주는 편이 낫겠다.) 실행권한도 빠져있으니 sudo chmod +x로 걸어주어야 한다.

이렇게 하고 나서 다시 sudo passenger-install-apache2-module 를 해 보면 뭔가 make 한다는 메시지가 쫙 나오고 나서 다음과 같은 텍스트가 화면에 출력된다.

Please edit your Apache configuration file, and add these lines:

   LoadModule passenger_module /var/lib/gems/1.8/gems/passenger-2.0.2/ext/apache2/mod_passenger.so
   PassengerRoot /var/lib/gems/1.8/gems/passenger-2.0.2
   PassengerRuby /usr/bin/ruby1.8

After you restart Apache, you are ready to deploy any number of Ruby on Rails
applications on Apache, without any further Ruby on Rails-specific
configuration!

Press ENTER to continue.

/etc/apache2/conf.d 디렉터리 아래에 passenger라는 파일을 만들어 위의 설정을 그대로 입력해 보자. 그런 다음에 enter 키를 누르면 다음의 텍스트가 화면에 출력된다.

Deploying a Ruby on Rails application: an example

Suppose you have a Ruby on Rails application in /somewhere. Add a virtual host
to your Apache configuration file, and set its DocumentRoot to
/somewhere/public, like this:

   <VirtualHost *:80>
      ServerName
www.yourhost.com
      DocumentRoot /somewhere/public
   </VirtualHost>

And that's it! You may also want to check the Users Guide for security and
optimization tips and other useful information:

  /var/lib/gems/1.8/gems/passenger-2.0.2/doc/Users guide.html

Enjoy Phusion Passenger, a product of Phusion (www.phusion.nl) :-)
http://www.modrails.com/

Phusion Passenger is a trademark of Hongli Lai & Ninh Bui.

일단 여기까지 해서 설치는 끝났다. 이제 남은 일은 VirtualHost 설정을 적절히 해서 Rails의 실행 결과가 브라우저에 전송될 수 있도록 하는 것 뿐...

우선, apache에 또다른 VIrtualHost 설정을 꾸며서, 접속 도메인 명이 달라질 경우 해당 VirualHost가 실행될 수 있도록 한다.

<VirtualHost *>
    ServerAdmin byungjoon.lee@gmail.com
    ServerName www.xxxxx.com
    DocumentRoot /home/bjlee/work/rails/xxxxx/public
    RailsBaseURI /
</VirtualHost>

대략 위와 같이 하면 된다. 다만 한가지 주의할 것은, 위의 /home/.../public 디렉터리에 www-data (apache2가 실행되는 사용자명) group에 대한 읽기쓰기 권한을 주어야 한다는 것. 필자는 /home/.../work/rails 디렉터리에 가서 그 아래에 있는 모든 subdirectory에 대해 chown -R bjlee:www-data *를 실행하고, chmod -R g+w * 를 실행해 주었다.

이렇게 하고 나서 브라우저의 주소창에 www.xxxxx.com을 입력하고 접속해보면 접속이 된다. 접속이 안될 경우 해당 도메인 명이 등록이 안된 것이니 ㅋㅋ 윈도우의 hosts 파일을 고쳐서 등록된 것처럼 꾸며야 할 것.

그런데 이렇게 하면서 몇가지 프로그래머가 반드시 알아야 할 사항이 드러났는데.

1. development 모드에서는 *.rhtml의 확장자를 사용해 view template을 꾸밀 수 있었는데, production mode를 가정하는 passenger의 특성상 *.html.erb의 확장자가 아니면 인식을 못한다는 것. (Rails 2.0부터는 *.rhtml의 확장자는 더이상 사용하지 않으며, *.html.erb의 확장자를 사용해야 한다. 다만 현재로서는 하위호환성을 위해 *.rhtml을 Development 모드에서는 지원하고 있다.)

2. 원래 그런 건지 아니면 설정을 잘못해서 그런건진 몰라도 (아마 전자일듯) passenger를 사용해 rails 프로그램을 띄우면 소스코드를 바꿔도 그 결과가 바로 반영되어 실행되지는 않는다. (소스코드의 변경을 반영하려면 웹 서버를 다시 띄워야 한다.) 아마 production mode 로 release를 하는 것을 가정하는 passenger의 특성상 그러할 것. 물론 시간이 지나 모든 세션이 종료되고 난 뒤에는 수정된 코드가 다시 반영된다. :-) Rails app 디렉터리 아래에 tmp/restart.txt 파일을 'touch' 해도 된다. 이 경우에는 웹 서버 전체가 재시작되는 것이 이니라, 해당 app만 재시작된다.

여기까지만 주의하면 passenger를 통해 rails 프로그램을 쾌적하게 배포할 수 있을 것이다.

다른 문제에 대해서는 passenger를 배포하고 있는 웹 사이트에 가서 http://www.modrails.com/ 사용자 가이드를 보면 될 것이다.




Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/145 관련글 쓰기

댓글을 달아 주세요

Languages/Erlang2008/06/14 17:03
Erlang 웹 개발을 위해 yaws 서버 소스 파일을 다운로드 받아 설치할때는 다음과 같은 절차를 우선적으로 밟게 된다.

./configure ; make

그런데 ./configure를 실행하면 gcc에서 실행파일을 생성할 수 없다고 하는 메시지가 뜨면서 configure가 중단되는 경우가 있다.

그런 경우에는 이 글을 참고하여 gcc 문제를 먼저 해결해야 한다. 그런 다음에 다시 ./configure ; make 한다.

그런데 make를 진행하다 보면 pam_appl.h라는 헤더 파일을 찾지 못한다는 오류 메시지가 출력되면서 컴파일이 진행되지 않는 경우가 있다.

그런 경우에는 sudo apt-get install libpam0g-dev 를 실행하여 관련된 헤더 파일을 설치하여야 한다.

이상의 과정이 정상적으로 끝났다면 이제 ./configure ; make를 하면 yaws 파일이 정상적으로 생성된다.

생성된 실행 파일을 설치하는 것은 그 나중 문제인데, 사용자의 local home directory에 임시로 설치하여 사용하고자 한다면 그 상태에서 make local_install 하면 된다. 그러면 실행 파일이 사용자의 $HOME/bin에 설치되고, configuration 파일은 $HOME/yaws.conf와 같이 만들어지게 된다.

개발 단계에서는 이렇게 설치해놓고 사용하는 것이 보다 간편하다.

상기 문제는 yaws 소스를 컴파일하여 설치하려고 하는 경우에만 발생하며, sudo apt-get install yaws와 같이 해서 설치한 사용자에게는 발생하지 않는 문제이다. 다만 sudo apt-get install yaws로 설치한 사용자는 Yaws 사용자 가이드에 나온 예제들을 실행해 보기 위애서 여러 가지 설정 파일들을 이리 고치고 저리 고치는 수고를 좀 장시간 해 주어야 할 것이다.

참고한 링크들:

  1. http://marc-abramowitz.com/archives/2007/04/18/building-yaws-erlang-web-server-for-ubuntu/
  2. http://www.buggymind.com/137
  3. http://www.ibm.com/developerworks/kr/library/opendw/20080520/





'Languages > Erlang' 카테고리의 다른 글

Erlang for C programmers (1) : 타입과 변수  (0) 2008/09/01
Erlyweb 개발 입문시 발생하는 문제 해결법  (0) 2008/07/04
Ubuntu에서의 yaws 설치 오류  (0) 2008/06/14
Programming Erlang  (2) 2008/06/12
Erlang GS 모듈 폰트 관련 예제  (2) 2008/04/23
Programming Erlang  (0) 2008/04/17


Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/138 관련글 쓰기

댓글을 달아 주세요

Languages/Ruby or Rails2008/06/13 10:03

제가 번역했던 Beginning Ruby on Rails 책을 구매하신 분중 두 분깨서 다음과 같은 오류를 지적해 주셨습니다. 해결책을 포스팅하겠다고 약속했었는데 늦어서 죄송합니다.

이 문제는 Rails가 sqlite3를 기본 database로 사용하게 되면서 빚어진 문제입니다. MySQL을 데이터베이스로 사용하려면 rails <app name> --database=mysql 과 같이 해주어야 합니다. 그렇게 하지 않으면, 지적된 오류가 발생하게 됩니다.

Windows

Ruby 1.8.6 버전을 Windows에 설치한 다음 gem을 통해 rails를 설치하고 Rails 프로그램을 만들어 돌려보면 no such file to load -- sqlite3 라는 오류가 발생하는 것을 보게 됩니다. 이 오류의 원인은, Rails가 sqlite3를 기본적으로 설치하지 않는데서 빚어지는 것입니다. 따라서, 이 오류를 교정하기 위해서는 다음과 같은 절차를 밟아야 합니다. sqlite3를 설치하기 위한 절차입니다. 현재로서는 Windows에서 발생한 경우만 확인되었으므로, Windows에서의 해결방법을 기준으로 말씀드리겠습니다.

1. http://www.sqlite.org/download.html을 방문합니다.

2. 화면 좌측의 Precompiled Binaries for Windows 섹션에서 sqlite-3_5_9.zip과 sqlitedll-3_5_9.zip의 두 파일을 다운로드 받습니다. 이 두 파일의 압축을 ruby 설치 디렉터레 아래의 bin 이라는 이름의 서브디렉터리에 풀어 놓습니다. 그 결과 해당 디렉터리 아래에 sqlite3.exe sqlite3.dll sqlite3.def의 세 가지 파일이 생겨있어야 합니다.

3. 그런 다음에 명령행에서 gem install sqlite3-ruby를 실행합니다. 화면에 여러 가지 옵션들이 나오게 될텐데, 1번 옵션에 나오는 sql3-ruby 1.2.2 (mswin32)를 선택합니다.

Bulk updating Gem source index for: http://gems.rubyforge.org
Select which gem to install for your platform (i386-mswin32)
 1. sqlite3-ruby 1.2.2 (mswin32)
 2. sqlite3-ruby 1.2.2 (ruby)
 3. sqlite3-ruby 1.2.1 (mswin32)
 4. sqlite3-ruby 1.2.1 (ruby)
 5. Skip this gem
 6. Cancel installation
> 1

위와 같이 하면 이제 sqlite3가 설치될 것입니다. 여기까지 하면 sqlite3 관련 오류는 해결이 되어야 합니다.

Linux (Ubuntu)

Ubuntu에서는 원래

sudo apt-get install sqlite3
sudo gem install sqlite3-ruby

위의 두 과정이 제대로 수행되면 문제가 없이 되어야 합니다.
그런데 간혹 두 번째 명령을 실행하다가 no such file to load -- mkmf 라는 메시지가 나오면서 설치가 제대로 안되는 경우가 있습니다. 그런 경우에는

sudo apt-get install ruby1.8-dev

위의 명령을 먼저 실행해 줍니다.

그런 다음 다음과 같이 하면 됩니다.

bjlee@bjlee-ubuntu804:~$ sudo gem install sqlite3-ruby
Select which gem to install for your platform (i486-linux)
 1. sqlite3-ruby 1.2.2 (mswin32)
 2. sqlite3-ruby 1.2.2 (ruby)
 3. sqlite3-ruby 1.2.1 (mswin32)
 4. sqlite3-ruby 1.2.1 (ruby)
 5. Skip this gem
 6. Cancel installation
> 2

그러면 다음과 같은 메시지가 주욱 나오면서 설치가 될 것입니다.

Building native extensions.  This could take a while...
Successfully installed sqlite3-ruby-1.2.2
Installing ri documentation for sqlite3-ruby-1.2.2...
Installing RDoc documentation for sqlite3-ruby-1.2.2...

이제 웹 서버를 내렸다가 다시 올리기만 하면 문제가 해결되어야 합니다.

감사와 사죄의 말씀

이 오류를 지적해주신 분은 킹상수님과 딸기벌레님, 두분입니다. 답변은 구글에 문의하면 찾을 수 있는 내용이긴 합니다만, 제가 빠른 답변을 드리겠다고 해 놓고 답을 제때 못드려서 죄송하다는 말씀, 다시한번 드립니다.

질문주신 두분께는 메일로 따로 연락드리도록 하겠습니다.





Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/135 관련글 쓰기

  1. 연군의 생각  삭제

    2010/02/04 14:45TRACKBACK FROM chiwoochun's me2DAY

    이 문제가 아닐까 추정하고 타임워커 님이 알려준 MAMP 설치 후 재 시도중.

  2. 이군의 생각  삭제

    2010/04/13 01:16TRACKBACK FROM e2goon's me2DAY

    이 책의 발행일은 2008년 2월 5일이며 ROR에서 mysql이 기본적으로 설치되어 있는 구버전의 기준으로 하여 안내하고 있다. (현재는 mysql 대신 sqlite3가 기본으로 제공된다.) ROR 갓 입문하신 분들은 착오 없으시길. 해결법, sqlite3둘러보기

댓글을 달아 주세요

  1. 까아~

    이게 문제였군요!! ㅠㅠ 안되서 설치만 여러번 한것 같아요...
    감사합니다. ^ㅡ^ 책은 구매해서 잘 보고있어요. 행복한 하루 되세요..

    2008/08/29 10:08 [ ADDR : EDIT/ DEL : REPLY ]
    • 감사합니다. 앞으로도 궁금한게 있으시면 자주 들러주시기 바랍니다. ^^

      2008/08/29 11:20 [ ADDR : EDIT/ DEL ]

Languages/C++2007/12/06 15:48

C++ 프로그래밍을 하다 보면 간혹 이와 같은 희귀한 오류 메시지를 만나게 되는 경우가 있습니다. 보통 다음과 같은 양상으로 나타나게 되는데요.

pure virtual method called
terminate called without an active exception

이런 오류 메시지가 나타나는 원인은 이렇습니다. 다음 코드를 보시죠.

class A {

public :
    A() {}

    void init() {
        ....
        virtual_method();
        ....
    }

    virtual void virtual_method() = 0;
};

class B : public A {

public :
    B() {}

    void virtual_method() {
        using namespace std;
        cout << "this is the implementation of pure virtual function A::virtual_method()\n";
    }
};

어디서 많이 보던 패턴이죠? ^^ 상위 클래스에는 알고리즘의 골격만 들어가고, 하위 클래스에는 해당 알고리즘을 구성하는 부분 알고리즘(위의 경우에는 virtual_method())의 실제 구현이 들어가는 그런 구조입니다. 알고리즘의 전체 골격은 바뀌지 않으면서, 그 세부사항만 하위 클래스에 따라 달라질 때 유용한 구조입니다.

그런데 이런 식으로 하는 것 자체에는 그다지 문제가 없는데, 문제는 init()을 호출하는 위치를 A 클래스의 생성자 안으로 이동시키게 되는 순간 발생합니다.

class A {

    void init() {
        ....
        virtual_method();
        ....
    }

public :
    A() {
        init();
    }

    virtual void virtual_method() = 0;
};

겉보기에는 꽤나 그럴싸하죠. B bb; 하는 순간 B 객체에 포함된 A 부분이 생성될 테고, A 부분은 자신의 멤버 변수 초기화를 마친 다음에 init() 함수를 불러서 알고리즘을 구동시키고, 그러면 그 알고리즘의 일부로 B 클래스에 정의된 멤버 함수가 자동적으로 호출되어 객체 전반적인 초기화를 완료하는...

그런데 이런 식의 초기화는 잘 될 턱이 없습니다. A가 private 함수 init()을 호출하는 순간 B::virtual_method가 호출되는데, 아직 객체 bb의 B 부분은 초기화가 되지도 않았거든요. -_- 그러니 B::virtual_method가 온전히 동작할 리가 없습니다. 사실 호출되는 것 자체가 불가능하죠. 객체 bb의 B 부분이 초기화되지 않았으니, 가상함수 테이블도 만들어지지 않았을 테니 말이에요.

그러니 위의 코드는 컴파일은 잘 됩니다만 (그러니 프로그래머는 '모든 순수 가상함수들을 구현했다니깐!'하는 식으로 착각하게 됩니다) 실제로 돌려보면 런타임에는 해당 가상함수의 구현이 발견되지 않습니다. 그래서 컴파일 시간이 아닌 실행 시간에

pure virtual method called
terminate called without an active exception

이런 괴상망칙한 오류가 발생하게 되는거죠. 나는 분명 구현했는데 그 함수가 아직도 '순수 가상 함수라니...' 정말 짜증나는 상황이지 않나요? ㅋㅋ

Effective Java라는 책에서도 지적되었던 것 같습니다만, 이런 이유로 해서 상위 클래스의 '생성자'안에서 하위 클래스의 메소드를 호출하는 것은 불가능하거나, 가능하더라도 피해야만 합니다. 설사 저런 오류가 나지 않더라도, 초기화되지 않은 메모리에다가 뭔 짓을 하려고 하면 그게 제대로 될 리가 없거든요.

- - -

이 글을 쓰고 웹 서핑을 하다보니 Meyer 선생도 자신의 저서(Effective C++ 3rd Edition, Item9)에서 같은 문제를 지적했더군요.

Never call virtual functions during construction or destruction.

이 문제에 대한 좀 더 상세한 지식을 얻고 싶으시다면, 여기에 가보시는 것도 좋겠습니다. :-)

'Languages > C++' 카테고리의 다른 글

VI와 ctags  (0) 2007/12/18
empty container의 반환  (0) 2007/12/14
메모리 할당과 초기화는 다르다  (2) 2007/12/14
Destructor가 왜 2번 불리는 거죠?  (0) 2007/12/12
pure virtual method called  (2) 2007/12/06
stringstream  (2) 2007/12/04


Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/84 관련글 쓰기

댓글을 달아 주세요

  1. yakkle

    클래스 A 에서 void virtual_method() = 0; 가 virtual void virtual_method() = 0; 로 바뀌어야 하지 않나요?
    문제 상황을 재현해 보려다가 안되길래 글 남깁니다.

    2009/06/12 10:24 [ ADDR : EDIT/ DEL : REPLY ]

Books by Example/SICP2007/11/09 00:13
밤마다 한시간씩 SICP 문제를 풀어보고 있습니다. 오늘은 1.8을 풀어봤습니다. Scheme 언어에 익숙해지려면 아무래도 시간이 좀 많이 걸리겠군요. 문제 1.8은 이렇습니다.

세제곱근 cube root를 구하는 뉴튼 법은, x의 세제곱근에 가까운 값을 y라고 할 때 다음 식에 따라 y보다 더 가까운 값을 계산하는 것이다.

(x + y^2 + 2y) / 3

제곱근 프로시저처럼, 이 식을 써서 세 제곱근 프로시저를 짜보자.


글쎄 뭐 짜는 것 까지는 좋습니다. 다음과 같은 코드를 작성했습니다.

(define (cube_root x)
  (if (or (= x 0) (< x 0)) 0 (cube_root_iter 1.0 x)))

(define (cube_root_iter guess x)
  (if (good_enough? guess x) guess (cube_root_iter (improve guess x) x)))

(define (good_enough? guess x) (< (/ (abs (- (cube guess) x)) x) 0.01))

(define (cube x) (* x x x))

(define (improve y x) (+ (/ x (* 3 (* y y))) (/ (* 2 y) 3)))

(cube_root 5)


이 간단한 코드를 짜는 데만도 한시간이 걸렸습니다. 그런데 처음에는 이상하게 값이 잘 안나오고 무한루프에 빠지더군요. 의심가는 데가 있어서 google에게 물어봤는데, 아무래도 책(번역판)에 나온 뉴튼법 공식이 좀 잘못된 것 같습니다. 다음과 같이 되어야 할 것 같습니다. (책에 나온 수식의 첫 번째 +가 /로 바뀌면 됩니다.)

사용자 삽입 이미지

위의 코드에서 빨간색으로 표시된 부분이, google이 알려준 뉴튼법 공식에 따라 수정된 부분입니다. 이렇게 고치고 나니, 프로그램이 정상적인 결과를 내 놓았습니다.

이 오류가 한글판의 오류인지 아니면 원서의 오류인지 잘 모르겠어서 구글신에게 다시 물어봤습니다. 한글판의 오류입니다. -_-; 좋은 책입니다만, 40페이지를 넘어가기도 전에 오류를 하나 발견하고 나니 어쩐지 맥이 빠지는 기분입니다[각주:1].

이런 기분인거냐?

이런 기분인거냐?



아무튼, 매일 잠들기 전에 하나씩 풀어볼 문제가 생겼다는건 기분 좋은 일이로군요. 아 이제 선형 대수학 책도 봐야하는데... -_-
 

  1. 역자분들의 노고를 폄하하거나 할 의도가 없음을 밝혀둡니다. 어쨌든 좋은 책이고, 사람이란 실수를 하게 마련이니까요. [본문으로]


Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/72 관련글 쓰기

  1. SCIP Exercise 연습문제 1.8  삭제

    2007/12/18 12:46TRACKBACK FROM NoSyu의 주저리 주저리

    이 문제는 세제곱근을 구하는 프로시저 제작입니다. &nbsp; 해당 문제에 나오는 식을 보기 전에 Newton's method로 구해보았습니다. (관련글 : 'Newton의 방법(Newton's method)') 그런 후 책을 살펴보니 식이 전혀 다릅니다. 그래서 제가 틀렸다고 생각해 좌절하고 프로시저를 제작하였습니다. &nbsp; 하지만 무한루프를 계속 돌더군요. 그 이유가 무엇일까 코드를 아무리 살펴봤지만 알 수 없었습니다. &nbsp;...

  2. SCIP 연습문제 1.8  삭제

    2008/01/23 12:56TRACKBACK FROM 탱이의 세상만사

    참으로 허무한 문제다. 분명 나의 계산에는 이상이 없었다. 보고 또 보고, 계속 봐도 나는 틀린게 없었다. 뭐가 문제지? 답은 책이 잘못된 것이었다..... 관련 링크 : http://www.buggymind.com/72 한참을 끙끙대다가 인터넷의 도움을 받기로 하고 검색한 결과 어이없는 내용없다...(하하...) 문제인즉, 세제곱을 구하는 공식이 틀렸던 것이다. 아래의 공식이 정확한 공식이다. 아래는 바뀐 코드 내용이다.

  3. Kr015se의 생각  삭제

    2008/07/11 12:02TRACKBACK FROM kroisse's me2DAY

    SICP 초반부터 고작 연습문제에 난 오자 하나 때문에 무쟈게 고생 ㄱ-;; 찾아보니 같은 데서 낚인 사람들이 꽤 되는 듯

댓글을 달아 주세요

  1. Programming Pearls 를 다 보고 이 책을 보려고 작정하고 있습니다. 나중에 연습 문제 풀 때 여기 자주 와야 되겠네요. 전 이거 두권이면 올 겨울은 그냥 지나갈 듯 합니다. ㅎㅎ

    2007/11/09 10:29 [ ADDR : EDIT/ DEL : REPLY ]
  2. 명백한 오타네요. ㅡㅡ;;
    사람의 일이라 피하기 힘들다지만... 이런 사항이 보고될 때마다 가슴이 두근두근 댑니다.
    또 다른 대형 사고는 없는지.... 얼마나 더 지나야 안심할 수 있을런지.... 휴~

    지적하신 사항은 오탈자 사이트에 반영해 놓겠습니다.

    2007/11/09 15:48 [ ADDR : EDIT/ DEL : REPLY ]
  3. 어쩐지 제가 뉴튼법으로 구한 식과 책에 적혀있는 것이 다르다고 했습니다.OTL....

    2007/12/18 12:35 [ ADDR : EDIT/ DEL : REPLY ]
    • 그래도 오자 하나 발견할때 마다 배우는 것이 있어서 좋지 않습니까? ㅋㅋ

      2007/12/18 13:35 [ ADDR : EDIT/ DEL ]
  4. 저도 같은 일을 겪었어요. 어쩐지 값이 안 나와서 뒷장의 뉴튼 부분을 참고하니 풀리더라고요. :)

    2008/08/31 15:44 [ ADDR : EDIT/ DEL : REPLY ]