Rust でう~ん?と思うところのメモ
expect というメソッド名
Perl の die() に似ている関数で、エラーメッセージを出してプログラムを強制終了(Rustでは panic!()) する Result 型にあるメソッド。
APIリファレンス(↗)をみると、 引数に渡すメッセージがどうあるべきか(Common Message Style ↗)まで 指定されているんだけど、The Book のサンプルコード見てても、それに従ってないような気がする。
expect という関数名も、そのメッセージスタイルに従うことを前提として関数名を決めたみたいなんだけど、 この関数名のせいで、コードが読みにくくなっている気がする。いわゆる、不適切な命名*1にみえてしまう。
まだ Rust になじんでないだけかもしれないけど。
Common Message Style も一応読んで見たけど、まだピンとこない。
- エラーが起こる
- どんなエラーかをプリントする。
というのは悪いスタイルらしく
- エラーが起こる
- 何を期待していたか(どうしていればエラーを回避できたか)をプリントする。
というルールがよいとしている。 でも、まず、エラーが起こったことを教えてほしいな。どうすればエラーを回避できたかはその後な気がする。 まあ、panic! するので、何らかのエラーが起こったことは分かってるはずだから、回避方法だけ書けばよい! という意図のようだけど。 (あと、エラーが出たときにプログラマがコードを見て、何を期待していたか書いてあるとわかりやすいという意図もあるらしい)
うーん。慣れれば使いやすいのだろうか。まだ分かってない。 まあ、panic! の出力をそのままユーザーに見せること自体、製品レベルのコードではあり得ないだろうから、そこまで気にしなくてよいのかもしれないけど。
ヒープ多用
ヒープの利用を前提としているところが多いような印象。 まあ、String, Vector, Box なんかは仕方ないにしても、 動的な多相性を dyn を使って実現するときも、ヒープメモリの利用が欠かせないように読めたけど、どうだっけ?
あと、すべてのエラーを表すのにも動的な多相性(dyn)を利用するので、エラー処理を統一したいとか思ってもヒープ必要になりそうな?
日本の組み込み開発では、ヒープはなるべく使わないというところもあるので、そのへん普及の足かせになりそう。
まあ、起動時にヒープを取得してずっと使い続けるような運用なら問題はなさそうだけど。
※ヒープの獲得と解放を繰り返すときの問題点
- メモリが断片化して、いつか必要な量のメモリが確保できなくなる恐れあり。
- ヒープ獲得時にはロックが必要なので、リアルタイム性確保のためにその遅延が許されない場合もある。
- 組み込みでヒープ使うときはアロケートシステムを独自実装することになるだろうから、難易度が高いかも。
組み込み開発でRustを使うなら、ヒープも使う方向に舵を切るべきかも。
Rustを使ったLinuxカーネルドライバの開発では、ヒープも使っているぽい映像(↗)あった。 もともとLinuxはヒープ使うのを、ためらったりしてないのかな。
Rust でグローバル変数にアクセスするときは常に Mutex 必要(unsafe という選択肢もあるけど)
- 同一タイミングに同じ領域に同時アクセスしないことによる排他
という、運用上の排他が行われていることもある。タイミング管理を人間が行う必要があるけど、 OSが提供するロック機能を使う必要が無いので、遅延がないのが利点。
まあ、ロックする時間はちょびっとなので、これはRustによる排他制御を受け入れた方が 不具合は減りそうだから、そのほうがいいかな。
ただし、Mutex とか Arc とか使うときも、どうやらヒープを使うみたいなのでそっちの方がネックかな。
LinuxのカーネルドライバをRustで開発するChatGPTが生成したらしき例Gistみると、 Linux との界面は unsafe にしておいて、C と Rust を切り分けてるみたい。
ドライバ用のデータは、C側に持たせておいて、unsafe な API 呼ぶときに渡してもらうようにしているらしい。 これなら、自分でグローバル変数持たずにすむから Rust で Mutex とる必要もないか。
これを、Rust単体でやろうとすると、結局グローバル変数にアクセスするところはすべて unsafe にしておいて 残りは unsafe でないコードでやる感じかな。(レジスタアクセスは unsafe になるだろうけど)
一部の日本語訳にう~ん?
"トレイト境界" → トレイト制約 のほうが好き
trait bound の日本語訳。
トレイトに対して制約を加える機能なので、トレイト制約がよいと思う。
オライリーの『プログラミングRust 第2版』でもトレイト制約を採用しているし。
トレイト境界という日本語はわかりにくい。
bound という英語には、境界線によって区切られた一定の領域の内側、という、「面」的な意味があるようで、 おそらくその意味で bound を使っているんだろうけど、 境界という日本語から最初に想起されるイメージは、領域を区切る一本の線だと思う。なので、意味の脱落が生じている気がする。 (境界をキョウガイと読む場合は、領域に近い意味もあるようだけど、境界はキョウカイと読むほうが多いだろうし)
"デストラクト" → 分割代入 とかのほうがよさそう。
destructuring の日本語訳。
”デストラクト" より、分割代入とかの方がいいな。 そもそも、destructuring と destruct とは、英語でも意味が異なるようなので、destructuring を "デストラクト" と訳すのは単純に間違っていそうな気がする。
destructuring は
fn main() { let arr = [100, 200]; let [first, second] = arr; println!("Hello, world! {first}, {second}"); }
みたいなコードのこと。(上のコードでは、配列の内容を first と second という変数に代入している)
JavaScript では分割代入(↗)、
またはそのままデストラクチャリングと訳されている様子。
C++ では構造化束縛(structured bindings)(↗)という。
デストラクトというと、C++プログラマからみると Destructor (クラスの破棄関数)と思っちゃうので困る。
ちなみに、Rustで C++ の Destructor に対応するのは Drop トレイトの drop() メソッド。
Rust Memo
Rust 本家
Rust本家
ドキュメント
標準ライブラリのリファレンス
Playground
Rust By Example (RBE)
Introduction - Rust By Example
.
この記事は主に RBE をベースにしている。
Rustインストール後は rustup doc
でローカルのドキュメントをブラウザで表示できる。
Hello World など
Hello World
fn main() { pirntln!("Hello World!"); }
FizzBuzz
fn main() { fizz_buzz(); } fn fizz_buzz() { for i in 1..=100 { let mut s = ""; if i % 15 == 0 { s = "FizzBuzz"; } else if i % 3 == 0 { s = "Fizz" } else if i % 5 == 0 { s = "Buzz" } if (s.len() != 0) { println!("{}: {}", i, s); } } }
Rustc
rustc は、Rust のコンパイラ。
通常は直接使わず、 cargo 経由で実行される。
Cargo
cargo (カーゴ)は Rust のプログラムをビルドするツール。
Rust の外部パッケージ(crate (クレート)と呼ばれる)のパッケージマネージャでもある。
crate は https://crates.io で公開されている。
Cargo.toml に、追加で必要な crate を記述しておくと cargo はビルドに先立ち crate.io からその crate をダウンロードする。
(※ 自分で書くプログラムも crate と言う)
$ cargo new my_app # 作業環境の作成 $ cargo new --lib my_lib # ライブラリ作成用作業環境の作成 $ cd my_app $ cargo build # デバッグビルド ==> target/debug/my_app ができる。 $ cargo build --release # リリースビルド ==> target/release/my_app ができる $ cargo check # ビルドせず、コードのチェックだけしてビルドはしない。 $ cargo run # 実行 (./target/debug/my_app でも実行できる) $ cargo doc # target/doc にドキュメントを生成 $ cargo -h # cargo の使い方 $ cargo build -h # cargo build の使い方
コメント
コメント
// ラインコメント /* ブロックコメント */ /* * ブロックコメント */
Doc Comment
///
で Doc コメントを書くことができる。 関数や、構造体に Doc コメントを書いておくと、cargo doc
で生成されるドキュメントにその記述が反映される。
生成される場所: target/doc/my_app/index.html
Doc コメント内では Markdown がサポートされる。
Documentation - Rust By Example
/// 四角形を表す構造体 struct Rectangle { left: u32, top: u32, width: u32, height: u32, }
文字列のフォーマットとプリント
Rust では、コンソールへの出力や、文字列のフォーマットは println! や format! といったマクロを使う。(! がつくものはマクロ)
Rust の関数は現状可変個引数に対応してないのでマクロでやるしかない。
format!
String 型の文字列にフォーマット結果を書き込んで返す
print!
format! と同じだけど、標準出力にプリントする
println!
print! と同じだけど、改行も出力する
eprint!
標準エラー出力にプリントする
eprintln!
eprint! と同じだけど、改行も出力
fn fmt() { let s = format!("{}", "Hello"); print!("{}\n", s); println!("{} World", "Hello"); println!("{} + {} = {}", 1, 2, 3); println!("My name is {0}, {1} {0}.", "Bond", "James"); println!("My name is {bond}, {james} {bond}.", bond="Bond", james="James"); println!("dec: {num}, oct: {num:o}, hex: {num:x}, bin: {num:b}", num=15); println!("{:?}", ("Hello", "World")); #[derive(Debug)] struct St(i32); println!("{:?}", St(32)); println!("{:#?}", St(32)); }
Hello Hello World 1 + 2 = 3 My name is Bond, James Bond. My name is Bond, James Bond. dec: 15, oct: 17, hex: f, bin: 1111 ("Hello", "World") St(32) St( 32, )
"{:?}"
はデバッグ用のフォーマット指定。
"{:#?}"
も同じだが、構造体のメンバなど、見やすく表示してくれる(Pretty Print)
デバッグ用のフォーマットは、デフォルトでは、標準ライブラリ std
が提供する型にしか対応していない。
struct や enum で作るユーザー定義型は fmt::Debug
トレイトを実装しないといけないのだが #[derive(Debug)]
とすることで自動的に実装を提供できる。
(必要な時に自動的にやってくれるようになるとよいのだけど)
"{}"
に対する有効なテキストは fmt::Display
トレイトを自分で実装する必要がある。
プリミティブ
スカラー型
符号付き整数
i8 i16 i32 i64 i128 isize /// ポインタのバイト数ぶんの幅をもつ
小数点以下がない数値はデフォルトで i32
になる。
符号無し整数
u8 u16 u32 u64 u128 usize /// ポインタのバイト数ぶんの幅をもつ
浮動小数点数
f32 f64
小数点以下を含む数値はデフォルトで f64
になる
文字型(Unicode)
char
bool型
bool
ユニット型
()
空のタプルだけがユニット型になれる。何もないことを表すのに使われる。
複合型
配列
[1, 2, 3]
配列は同じ型のデータを複数保持する
タプル
(1, true)
タプルは異なる型のデータを複数保持する
変数に使う型
変数を宣言するとき、: <型名>
という形で、変数名の後ろに型を指定してもよい。指定しなくても多くの場合は型推論(inference)が働いて自動的に型が決定される。
fn variable() { // 型を指定してもよい let result: bool = true; // なくてもよい(true を代入しているので bool 型とわかる) let result = true; // 数値はデフォルトで i32 let num = 15; // 小数点付きの数値はデフォルトで f64 let float = 100.0; // 型サフィックス付き数値をいれるとその型になる。 let unsigned = 15u32; // 型推論システムが見ているのは初期値だけではない。 let mut var = 100; // i32 型のように思えるが、この段階ではまだ型は未確定で… var = 1_000_000_000u64; // ここで u64型が確定する。 // 下記のコードはエラー。型は途中で変更できない。 // var = true; // でも、同じ名前の変数を新たに導入して以降のコードで古い var を見えなくする // こと(シャドーイング)で型を変更したように見せかけることは可能。 let var = true; }
リテラル (Literals)
Literals and operators - Rust By Example
タプル (Tuples)
配列とスライス (Arrays and Slices)
Arrays and Slices - Rust By Example
カスタムタイプ (Custom Types)
Custom Types - Rust By Example
カスタムタイプは 2つ。struct と enum
構造体 (Struct)
列挙型 (Enum)
use宣言
Cのような Enum も可能
Enum を使ったリンクトリスト
Testcase: linked-list - Rust By Example
定数 (constants)
変数の束縛 (Variable Bindings)
Variable Bindings - Rust By Example
let
変数はデフォルトでは書き換え不可 (Mutability)
スコープとシャドーイング (Scope and Shadowing)
Scope and Shadowing - Rust By Example
初期化の遅延 (Declare first)
Declare first - Rust By Example
滅多に使わない
初期化忘れのコンパイルエラーになりやすい
変数を一時的に不変にする (Freezing)
型 (Types)
組み込み型を別の組み込み型に変換する (Casting)
リテラルで型を指定 (Literals)
数値リテラルは、接尾辞として型を指定することで、型を明示することができる。 これをアノテーション(annotation:注釈) と呼んでいる様子。
let a = 255u8; let b = 0x100u16;
アノテーションがない場合、その変数の使い方をもとに型推論によって型が決まる。
なんら制約がない場合は、整数は i32 、浮動小数点数は f64 になる。
型推論 (Inference)
Rust の型推論エンジンはかなり頭がよいので、初期化コードだけでなく、初期化後の変数の使い方も見て型を決定する。
// 型アノテーションによって elem が u8 であることはこの場で確定。 let elem = 5u8; // 空のベクタ(可変長の配列) let mut vec = Vec::new(); // この時点では、まだベクタに格納される型は未確定なので、vec の型も未確定。 // コンパイラは、なんからのベクタであることだけを知っている。(Vec<_>) // ベクタに最初の要素をセット vec.push(elem); // ここで初めてベクタの型が確定する。(Vec<u8>)
型に別名をつける (Aliasing)
type
で型に別名をつけることができる。- 型は
UpperCamelCase
でないとウォーニングが出る。 #[allow(non_camel_case_types)]
というアトリビュートを指定すると、キャメルケース以外でもOK
type UInt = u32; #[allow(non_camel_case_types)] type uint32_t = u32;
type
の目的は、ボイラープレート (boilerplate) なコードを減らすため。
ボイラープレートとは、言語仕様からくる要請によって、プログラマが繰り返し書かされる同じコードのこと。
ジェネリックを使うと、型がどんどん複雑になるので短い名前をつける機能は必須になってくる。
アトリビュート (Attribute: 属性)
アトリビュートは、クレート、モジュール、アイテム(関数や構造体など)につけるメタデータ(追加情報)。
下記の用途で使う。
- 条件付きコンパイル
- クレートの名前、バージョン、タイプ(binary or library)を指定する
- ウォーニング(lints)の抑止
- コンパイラの機能(マクロ、globインポートなど)を有効にする
- 外部ライブラリとのリンク
- 関数を Unit テスト用とマークする
- 関数に、ベンチマークの一部になるもの、とマークする
クレート全体に適用する場合はファイルの先頭などで #!
をつけて指定する。(#!
は Inner attributes)
#![cfg(...)]
モジュールやアイテム(関数や構造体など)につける場合は !
をつけずアイテムの前に置く。(#
は Outer attributes)
#[cfg(...)] fn func() {}
アトリビュートには、いくつかの書き方で設定値を指定できる
#[attribute = "value"] #[attribute(key = "value")] #[attribute(value)]
アトリビュートは複数の値を持つこともできる。
#[attribute(For, Bar, Buz)]
複数行に渡って記述することも可能。
#[attribute(value0, value1, value2, value3, value4, value5, value6, value7)]
アトリビュートの詳細はこちら
Attributes - The Rust Reference
使わないコードへの warning を抑止するアトリビュート(dead_code)
コンパイラは使われていない関数には unused function とウォーニングを出す。 下記のアトリビュートを指定することで抑止できる。(ただ、現実の開発では使われていない関数は削除するほうがよい)
#[alllow(dead_code)] fn unused_func() { }
クレート全体に適用するには !
付きで書いておく
#![allow(unused)]
TBD: あれ dead_code と unused の違いは?
クレートにつけるアトリビュート
crate_type
アトリビュートでクレートがバイナリクレートか、ライブラリクレートを指定する。
ライブラリのタイプも指定できる。(TBD: それなに?)
#![crate_type = "lib"]
crate_name
アトリビュートでクレートの名前を指定する。
#![crate_name = "RingBuffer"]
ただし Cargo を使う Rust プロジェクトでは crate_type
, crate_name
は意味を持たない。(Cargo.toml で管理するためかな?)
たいていの Rust プロジェクトとは Cargo を使って管理するので、これらのアトリビュートはほとんど使われない様子。
crate_type
アトリビュートを使うときは rustc
の --crate-type
オプションは必要ない。
$ rustc mylib.rs
$ ls lib*
libmylib.rlib
crate_type
アトリビュートがない場合 rustc がエラーになる
$ rustc mylib.rs error[E0601]: `main` function not found in crate `mylib` --> mylib.rs:3:1 | 3 | / pub fn hello_mylib() { 4 | | println!("mylib"); 5 | | } | |_^ consider adding a `main` function to `mylib.rs` error: aborting due to previous error For more information about this error, try `rustc --explain E0601`.
cfg アトリビュート
条件付きコンパイルを制御する方法は cfg アトリビュートのほか、cfg_attr アトリビュートと cfg! マクロがある。
cfg アトリビュートによる条件コンパイル
通常は、条件コンパイルはコードの可読性を下げるのでアプリケーションを書くときは使わないように書くのが正しい。
が、HWリソースを節約したいときなどには、動かさないコードは実行バイナリに含めたくないので必ず必要になる機能。
#[cfg(target_os = "linux")] fn who_am_i() { println!("Linux"); } #[cfg(target_os = "windows")] fn who_am_i() { println!("Windows"); } /// any: foo または bar が定義されている場合コンパイルされる #[cfg(any(foo, bar))] fn needs_foo_or_bar() { } /// all: unix ファミリー、かつ、32bitアーキテクチャの場合のみ #[cfg(all(unix, target_pointer_width = "32"))] fn memcpy4byte() { } /// not: foo が定義されていないこと。 #[cfg(not(foo))] fn need_not_foo() { }
cfg_attr アトリビュート
cfg_attr アトリビュートは、第一引数が真なら、第二引数以降をそれぞれ '#[' と']' で囲んでアトリビュートを作り、自らをそのアトリビュートで置き換える。
うーん。うまい使い方が思いつかない。
cfg!() マクロによる条件コンパイル
fn main() { cond_print(); } fn cond_print() { let endian = if cfg!(target_endian = "big") { "Big Endian" } else if cfg!(target_endian = "little") { "Little Endian" } else { "??" }; println!("{}", endian); }
cfg アトリビュートで任意のオプション(Configration Option)を使う方法
rustc
の --cfg
オプションで任意の値を渡すことが可能。
$ rustc --cfg 'verbose' --cfg 'my_option="foo"'
この例では、コード中のアトリビュート #[cfg(verbose)]
と #[cfg(my_option="foo")
が有効になる。
feature オプションは Cargo で予約
feature
オプションは Cargo によって設定される Configuration Option なので、使わない方がよさそう。
Cargo.toml で [features] を設定する方法はこちら
Features - The Cargo Book
組み込みの cfg オプション
- target_arch
- target_feature
- target_os
- target_family
- unix
- windows
- target_env
- target_endian
- target_pointer_width
- target_vendor
- test
- debug_assertions
- proc_macro
詳細はこちら
Conditional compilation - The Rust Reference
モジュール
WSL に最新の ubuntu をいれる(emacsも apt install した)
Ubuntu 18.04 LTS というのを使っていたが、Windowsストアにバージョン無しの Ubuntu があるのでこっちも入れた。中身は Ubuntu 20.04 LTS らしい。 これまでバージョンがあがると別アプリになっていたけど、一本化したのかな。
1. Windows の機能の有効化または無効化で WSL にチェックをつける。
もうチェック済みだけど、はじめて入れる場合はやっておく必要がある。再起動必要らしい。
コントロールパネルのプログラムから実行できる。
Windows Subsystem for Linux にチェックを付ける。
2. Microsoft ストアから Ubuntu をインストール
スタートメニューをクリックして 「store」と入力すると 「Microsoft Store」が出てくるので実行。
右上の虫眼鏡アイコンをおして「ubuntu」で検索
検索すると、いくつかヒットする
一番左の「Ubuntu」をクリックすると下記画面になるのでインストールする。(もうインストール済みなので下図では「インストール」ボタンがないが、まだの場合は「インストール」ボタンがある)
インストール後、「起動」ボタンの右の「…」をクリックすると、「スタートにピン留めする」「タスクバーにピン留めする」があるので、とりあえずピン留めしておいた。(下図では文字色が灰色になってい見にくいが)
3. ubuntu の実行
タスクバーにあるアイコン をクリックとターミナルが起動する。
最初はユーザー名とパスワードの入力を求められる。 このユーザー名とパスワードは、あとで sudo とか root 権限で実行する必要があるときに使う。 入ってないソフトを apt でインストールするのにも必要。
Windows のユーザー、パスワードとは同じでなくてもよいらしい。
4. emacs のインストール
vim はシステム管理ツールという側面もあるで初めから入っているけど emacs は入っていないのでインストール。
まずは現状での最新版の取り込み。sudo するとパスワードを聞かれるので、ubuntu を最初に起動したときに入れたパスワードをいれる。
$ sudo apt upgrade # list を最新に更新するらしい $ sudo apt update # いまあるソフトを最新に更新
どんなソフトがあるか確認するのは
$ apt list # 一覧表示 (多いので apt list | less としたほうがいいかな) $ apt list emacs # emacs だけ表示 $ apt list *emacs* # ワイルドカードも使えるらしい $ apt search emacs # 説明欄に emacs という文字列をふくむパッケージを検索 $ apt show emacs # emacs パッケージの説明を表示
emacs のインストール
$ sudo apt install emacs
新しい consel-gtags.el を試してみたらパッチが必要だった
こまった
counsel-gtags--select-file-ivy-parameters でコールしている string-empty-p という関数がないようで動かない。
Symbol’s function definition is void: string-empty-p
とエラー終了。
対応
『やさしい Emacs-Lisp講座』を参考に scratch バッファで
- (setq debug-on-error t) <C-j> として、その後
- counsel-gtags-dwim を実行(タグジャンプしてみただけ)
- バックトレースが表示される。みると counsel-gtags--select-file-ivy-parameters でエラー発生。
- クリックしてエラー発生関数に飛び M-x edebug-defun する
- もう一度実行させて関数内をステップ実行。
として確認した。
(if (string-empty-p tagname) ...)
という記述を変更する。↓
(if (= (length tagname) 0) ...)
長さが 0 の判定にした。
修正後
emacs-lisp-byte-compile-and-load
でバイトコンパイルして再ロード。
最後に edebug-defun の効果を消すために対象関数の中で
C-M-x (eval-defun)
を実行。これでデバッグ機能なしのふつうの関数が再定義されるらしい。
参考資料
おわりに
以前も file-truename を呼ぶためにシンボリックリンクのファイルが開けない・・・という動きになってしまい file-truename を使わないようにしたことがあった。今回はそれは大丈夫なのかな??
2次方程式の新しい解法のおためし実装
2次方程式の新しい解法
↓ こんな記事を見かけた
天才数学者が二次方程式の簡単な解き方を考案!「推測も暗記も必要ない」 | ナゾロジー
計算だけで二次方程式が解けるそうな。
プログラムにしてみる
計算だけでできるならコンピュータ向き。 ためしにそのアルゴリズムを python で書いてみた。
niji.py
#!/usr/bin/python3 import os import sys import math # 二次方程式の計算 # @param a: x^2 の項の係数 # @param b: x の項の係数 # @param c: 定数項 # # @ref https://nazology.net/archives/49629 # https://arxiv.org/abs/1910.06709 # # @note 計算の概要 # x^2 - bx + c = 0 の二次方程式を (x-p)(x-q) の形にする。 # このとき p = b/2 + u, q = b/2 - u となる未知数 u を考える。 # すると # (x-(b/2+u))(x-(b/2-u)) = 0 # となる。このとき解は # x = b/2 + u, b/2 - u の2つ。 # これを ax^2 + bx + c = 0 で考えると解は # x = -b/2a + u, -b/2a - u ...(1) # である。 c は 2 つの解の積なので # c = (-b/2a + u)(-b/2a - u) # となり、これを計算すると未知数 u が得られる。 # c = (-b/2a)^2 - u^2 # u = sqrt((-b/2a)^2 - c) # あとは (1) 式に u を代入することで解を得る。 # x = -b/2a + sqrt((-b/2a)^2 - c), # -b/2a - sqrt((-b/2a)^2 - c) def quadratic_equation(a, b, c): center = (-1 * b) / (2 * a); gap = math.sqrt(center ** 2 - c) return center + gap, center - gap def print_qe(a, b, c): ans1, ans2 = quadratic_equation(a, b, c) print("ans1: ", ans1) print("ans2: ", ans2) def test(): print_qe(1, 2, 1) print_qe(1, -2, 1) print_qe(1, 4, 4) print_qe(1, -4, 4) print_qe(1, 6, 9) print_qe(1, -6, 9) print_qe(1, 10, 18) print("5+sqrt(7): ", 5+math.sqrt(7)) print("5-sqrt(7): ", 5-math.sqrt(7)) if __name__ == "__main__": test()
ふむふむ。 とりあえず動いてそう。
解の公式との違い
式を変形すると二次方程式の解の公式と同じになるらしい。
解の公式をプログラム化してみると・・・
# 解の公式 # x = (-b + sqrt(b^2 - 4ac)) / 2a, # (-b - sqrt(b^2 - 4ac)) / 2a def quadratic_equation_official(a, b, c): center = -1 * b gap = math.sqrt(b**2 - 4 * a * c) divider = 2 * a return (center + gap) / divider, (center - gap) / divider
プログラム化するときは割り算が一回で済む分、解の公式をそのままプログラム化するより、新しい方式のほうが有利かな。新しい方式のほうがかけ算の回数も少ないかな。
Windows10 で pip install がエラーになる例の件
本を買った
東京大学のデータサイエンティスト育成講座 Pythonで手を動かして学ぶデ―タ分析
説明にあるとおりに Anaconda をインストールして、 condas-datareader と Plotly を pip install でインストールしようとしたら pip install がエラーを吐く。
その回避方法
環境変数 Path に Anaconda3\Library\bin を追加する。 (但し Anacondaのインストール先はインストールしたときの設定によって変わるようですよ)
うちはこれで
pip install condas-datareader
pip install Plotly
がうまくいきました。(pip が Successfully installed と言ってる)
Special Thanks
下記のサイトを参考にさせていただきました。
https://github.com/conda/conda/issues/8046#issuecomment-456565256
Cygwin で java を動かす
Cygwin には java は付属してないみたい
setupで検索しても出てこない。
でもWindows でインストールしていれば使える
$ type java java は /cygdrive/c/ProgramData/Oracle/Java/javapath/java です
でも実行すると動かない
java -Dfile.encoding=UTF-8 -jar /usr/share/emacs/26.1/lisp/contrib/scripts/ditaa.jar /tmp/babel-cacHaR/ditaa-4QhER5 /home/someone/org/images/hello-world.png Error: Unable to access jarfile /usr/share/emacs/26.1/lisp/contrib/scripts/ditaa.jar
なぜなら、PATH が Windows 形式じゃないから
java に限らないが、ふつうのWindowのプログラムは、引数で受け取る PATH が Windows の PATH 形式じゃないと、うまく動けない。
Cygwin から実行されることは想定していないので、コマンドラインに指定した /usr/...
とか、いったいどこだ? と混乱する。
なので変換スクリプトを用意
#!/usr/bin/python3 # -*- python -*- # # Windows 向けの Java を実行する前に引数のファイル名を # Windows 向けの java が理解できるPATHに直す。 # import os import sys import re import subprocess JAVA_FOR_WINDOWS = "/cygdrive/c/ProgramData/Oracle/Java/javapath/java" def main(): argv = sys.argv[1:] #print(argv) option = [] args = [] for arg in argv: if arg.startswith("-"): option.append(arg) else: args.append(arg) #print(option) #print(args) args_win = [] for arg in args: cmdline = "cygpath -m " + arg #print(cmdline) ret = subprocess.check_output(cmdline, shell=True) ret = ret.decode() ret = ret.strip(); args_win.append(ret) #print("args_win=", args_win) argv = option + args_win #print("argv=", argv) cmdline = JAVA_FOR_WINDOWS + " " + " ".join(option) + " " + " ".join(argv) #print("cmdline=", cmdline) subprocess.check_call(cmdline, shell=True) if __name__ == "__main__": main()
これを ~/bin/java
として保存。実行権つけて本物の java より PATH 環境変数の前に置いといて先に実行されるようにしとく。
$ chmod 755 ~/bin/java $ export PATH=~/bin:$PATH
これで、java
を実行するとこのスクリプトが実行され、スクリプトの中でほんものの java
を実行する前に PATH をうまいこと変換する。