cscope
dyson
また新しい言語を見付てきたか? dysonと微妙に綴が似ているけど、言語なら、 Dylan の方だ。
dysonって、あの掃除機の代名詞になってる、人の名前だ。何でも、試作を 5126回も繰り返して、やっと満足がいくものが出来たそう。DC01て極めて分かりやすい名前で発売された。ダイソン・クリーナー Ver 01 て亊だな。 順調に売れて、うさぎ小屋仕様の日本向けに、DC12が発売されてる。
イギリスに生を受け、デザイン学校を卒業、就職。もちまえのエンジニア気質で、一輪の運搬車(通称、猫車)の改良に乗り出す。一番気になっている不便な所、ぬかるみで車輪が沈んでしまい思うようにならない所を改良。車輪じゃなくてボールね。これなら沈まないな。
これが売れて、自分で会社を起す。特許は会社のものとして登録。やがて会社が大きくなり、内紛で追い出されてしまう。特許は会社のものなんで、自由にならない。株式会社だと株主にも媚を売らないといけない。痛い勉強であった。
いちからやり直し。ボールを作る時に出るプラスチックの微細なごみを除去するにに、大型のサイクロン方式の集塵機が使われていた。これを使って目詰まりする紙フィルターを使わない掃除機が作れるのでは? かくして、5000回を越えるチャレンジが始まった。
キーテクノロジーになる技術は自社開発。だってよそから買ってくるなら、同業他者と同じになっちゃうでしょ。高速回転するモーターとか、コードレス掃除機のための電池。
副産物で、電気自動車まで作ってしまうけど、売れない亊が確定しちゃったので、涙をのんで撤退。
面白いものを作っているぞ。たとえば ドライヤーだ。モーターは高速回転ゆえ、人間が感知する周波数を越えてる。ゆえに無音。握る部分にモーターと羽の重い部分を収納出来たんで、ヘッド部分は極めて軽量。長時間ドライヤーを使う美容師さんに好評とか。
最近では、コロナの影響で、英国政府から大量の人口呼吸器の依頼を受けた。 でも、独壇場で医師が人口呼吸器を使うのは好ましくないって亊でキャンセル。損失が33億に上ったけど、損害賠償なしなかったとか。 面白い会社だな。
ジェームズ・ダイソン最新著書 を読んで面白かったので紹介。
そう言えば、vimもpatch 043,044 とか、永遠に改良が続いているな。エンジニア気質だね。 そうそう、昔vimをコンパイルした亊が有るんだけど、永遠とパッチファイルをDLして、パッチを当てるって作業が有ったな。懐しい思いでだ。
sakae@deb:~/src/vim$ git log|grep Author|sort|uniq -c | sort -nr | head -5 15549 Author: Bram Moolenaar <Bram@vim.org> 164 Author: Yegappan Lakshmanan <yegappan@yahoo.com> 96 Author: zeertzjq <zeertzjq@outlook.com> 63 Author: Dominique Pelle <dominique.pelle@gmail.com> 55 Author: LemonBoy <thatlemon@gmail.com>
断トツでオーナーが頑張っていますね。
ctags
前回、カーネルの閲覧用にctagsを思わず使っちゃった。で、ふと思ったんだ。ctagsってコマンドは、システムから供給されてる由緒正しいやつなんだろうとね。/usr/bin/に鎮座してた。ソース・ツリーにも登録されてたので、老舗ですな。 ならばみる鹿。その前に、何は無くともmanですよ。
DESCRIPTION ctags makes a tags file from the specified C, Pascal, Fortran, YACC, lex, and Lisp sources. A tags file gives the locations of specified objects in a group of files. Each line of the tags file contains the object name, the file in which it is defined, and a search pattern for the object definition, separated by whitespace. HISTORY The ctags command appeared in 2BSD.
結構昔からあるやつ。昔はLispとかPascalとかも幅を効かせていたんで、サポートされてたのね。その代わり現代言語はサポートしてない。だって、まだ誕生していなかったから。最近だと、沢山の言語をサポートした、universal-ctagsが主流だ。
そんな亊より、生成されるファイルのフォーマットまで説明してある。本当にそうなってるか、tagsを確認。
USWAP undo.c /^#define USWAP(x,y) { \\$/ add_line_node buf.c /^add_line_node(line_t *lp)$/ append_lines main.c /^append_lines(int n)$/
3つのパートに分れてるんだな。区切文字はTAB。いわゆるCSVならぬTSV形式だ。左がタグの名前、真ん中はそれが存在するファイル名、右側は、タグの位置を検索する為の検索ワード。あいまいさなく検索する為、完全一致の正規表現が指示されている。
このtagsの結果は標準形式だけど、ユニバーサル版だと、更に親切に、そのタグが変数なのか関数なのかの判別情報とか、型がエイリアスとかかなんていう情報も付加されている。
vbox$ wc * 585 2014 12336 C.c 7 22 176 Makefile 316 1217 7877 ctags.c 88 577 3634 ctags.h 162 582 4059 fortran.c 100 461 2949 lisp.c 109 523 3305 print.c 136 530 3740 tree.c 146 568 3549 yacc.c 1649 6494 41625 total
C.cとかlisp.cとかは、言語特有のtagを抽出するためのものだろう。参考までlisp.cを紐解いてみる。
/* * lisp tag functions * just look for (def or (DEF */ void l_entries(void) { :
lispの特徴は、(def とかが含まれている亊ってなってる。pascal/fortranは関数が似ているんで、微妙な判定をやってるね。ご苦労様ですよ。fortranを構造化言語に変身させたRatforも、fortran一族と見做してくれるのか。職人技であります。
ex
ctagsと対になるやつも見ておくか。/usr/src/usr.bin/viに鎮座してた。中には、 viとexってフォルダーが有ったけど、迷わずにexの中に突入。だって、コロンに続いて入力するからね。exのコマンドですよ、と、刑事っぽく推測。
そしてその中は綺麗に名前がついていたぞ。曰く、 ex_tag.c
と tag.h だ。
お決まりでヘッダーファイルの方を先にみる。
* Each Q is a TAGQ, or tag "query", which is the result of one tag. * Each Q references one or more TAG's, or tagged file locations. * * tag: put a new Q at the head (^]) * tagnext: T1 -> T2 inside Q (^N) * tagprev: T2 -> T1 inside Q (^P) * tagpop: discard Q (^T) * tagtop: discard all Q
はあ、exのtag関連キーバインドまで説明されてた。で、tagを辿って、行きつ戻りつするために、双方向のリンクリストになってるとな。
次はそれを使うCファイルの方。まず、目についたのが、関数の前方宣言
static char *binary_search(char *, char *, char *); static char *linear_search(char *, char *, char *);
前にカーネルのtagsを作るMakefileをみた。その時、さりげなくsortしてたな。ソートしとく気配りのあるユーザーなら、安心してバイナリーサーチするけど、いつもいつもソートされてるとは限らないだろう。判定はどうやってる?
オイラーの予想では、最初バイナリーサーチを実施、それに失敗したら、諦めてリニアーサーチでくまなく探索。それでも見付からないなら、そんなタグは無いってエラー。
つらつらコードを見ていったよ。
ctag_search(SCR *sp, char *search, size_t slen, char *tag) { MARK m; char *p; /* * !!! * The historic tags file format (from a long, long time ago...) * used a line number, not a search string. I got complaints, so * people are still using the format. POSIX 1003.2 permits it. */
long, long time ago って、遥昔の中学校の英語の教科書に出て来たフレーズだな。昔は余分な行番号も埋め込まれていたとな。そんなので、楽しんでいてはいけない。予想通りか追跡。
/* * ctag_sfile -- * Search a tags file for a tag, adding any found to the tag queue. */ static int ctag_sfile(SCR *sp, TAGF *tfp, TAGQ *tqp, char *tname) { : front = map; back = front + sb.st_size; front = binary_search(tname, front, back); front = linear_search(tname, front, back); if (front == NULL) goto done;
ざっと見こんなのが出てきた。予想が当っと糠喜びして、いいものやら? どうも誤解してるっぽいぞ、と、野生の勘が発動。
cscope
vimのマニュアルでtagsを調べていたら、関連で Cscopeの紹介 なんてのが有った。これ、昔から有る亊は知ってたけど、使った亊が無かった。 プロが勧めてくるぐらいなんで、使いこなしたら便利なんだろう。
Linuxカーネルソースコードを読むツール (1):cscope編
Vim で Linux カーネルソースを快適に読むための設定 具体例
上記でcscopeの使いかたはあらかた分るが、念の為本家を訪問。 CSCOPE
由緒あるツールなんですなあ。OSとか巨大なアプリの開発の副産物として現場から生れてきた感がプンプンしますよ。 やはりと言うか当然と言うか、名立たるEDITORから使えるようになってるね。
そうそう、これを起動してソースの閲覧したら、オリジナルのviが起動した。色がつかないviね。あれ、vimの場合は? 調べたら、環境変数EDITORに指定しとけとな。
ob$ EDITOR=vim cscope ob$ EDITOR=emacs cscope ob$ EDITOR=less cscope
ファイルを閲覧するツールを指定する亊が出来るので、上記のどれでもOK。
cscopeって、ググルみたいにファイル閲覧の為のインデックスを作る。ブラウザーで、何を検索するかユーザーに選ばせる。画層を検索?動画を検索?ニュースを検索? そして、出て来た候補を指定して貰うって亊をやるんだね。
実際の閲覧道具はユーザーの好みでfirefoxなりw3mを使ってくださいって亊と等価だ。ひょっとしてググルはcscopeにヒントを得たんじゃなかろうか。
となると、肝心なのは、ファイルをスキャンしてインデックスを作る部分だな。普通は -b を指定して、高速で検索出来るようにバイナリーにする。でも、-c を指定すると、インデックスがテキストファイルになる。
小さい例で実行してみる
このcscopeの実習として、lessでも選ぼうとしたんだけど、思っていたより規模が大きかったので、小粒なedを選んでみる。
ob$ cscope -b ob$ ls -l cscope.out -rw-r--r-- 1 sakae wheel 178481 Jul 26 07:06 cscope.out ob$ cscope -c ob$ ls -l cscope.out -rw-r--r-- 1 sakae wheel 214202 Jul 26 07:07 cscope.out
-cで起動すると、速やかにcscopeが起動するんで、びっくりしないように。で、テキスト版の方が、サイズが大きいね。でも、どんな風にインデックスが作成されてるか見られて、プチググルの秘密に迫った気分になれるよ。
折角なので、中を覗いてみる。検索対象は、 exec_command
153 int exec_command (void); 132 ( status = `exec_command ()) < 0 || 242 ( status = `exec_command ()) >= 0) 471 $exec_command (void)
cscopeを起動して、Find this C symbol: に指定してみた結果
C symbol: exec_command File Function Line 0 ed.h <global> 153 int exec_command(void ); 1 glbl.c exec_global 132 (status = exec_command()) < 0 || 2 main.c main 242 (status = exec_command()) >= 0) 3 main.c exec_command 471 exec_command(void )
Find this global definetion: に指定すると、関数定義はこの場合一箇所なんで、即座に定義部分が開く。戻ると、一応、こんな風になってた。
Global definition: exec_command File Line 0 main.c 471 exec_command(void )
こちらは、呼び出している所だな。
Functions calling this function: exec_command File Function Line 0 glbl.c exec_global 132 (status = exec_command()) < 0 || 1 main.c main 242 (status = exec_command()) >= 0)
次は、指定した関数の内容分析。中で使われている関数とマクロを列挙してくれる。ある意味、gdbで指定の関数内を彷徨っているみたいだ。この場合は、右側のlineの列に注目。気になったら、その関数に飛んで行けばよい。
Functions called by this function: exec_command File Function Line 0 main.c SKIP_BLANKS 488 SKIP_BLANKS(); 1 main.c GET_COMMAND_SUFFIX 491 GET_COMMAND_SUFFIX(); 2 main.c clear_undo_stack 492 if (!isglobal) clear_undo_stack(); 3 main.c append_lines 493 if (append_lines(second_addr) < 0) :
そして全文検索
Text string: exec_command File Line 0 ed.h 153 int exec_command(void); 1 glbl.c 132 (status = exec_command()) < 0 || 2 main.c 242 (status = exec_command()) >= 0) 3 main.c 468 /* exec_command: execute the next command in command buffer; return print 4 main.c 471 exec_command(void)
先に調べたテキスト版のcscope.outには、main.c 468行目のコメントは出てこなかった。不思議だなあと思ったぞ。 なんと、そういう勝手なユーザーにはDBを作り直して対応するしかないって亊で、バイナリーなやつになってた。こういう挙動なんですかね。
後、便利だなと思うのは、指定した変数に代入してる所を列挙してくれる機能。場合によっては、gdbで変数のチェンジを監視するより便利かも知れない。
Assignments to this symbol: status File Line 0 glbl.c 131 if ((status = extract_addr_range()) < 0 || 1 glbl.c 132 (status = ()) < 0 || 2 main.c 130 int status = 0; 3 main.c 186 status = -1; 4 main.c 214 status = ERR; 5 main.c 229 status = EMOD; 6 main.c 237 status = ERR; 7 main.c 241 if ((status = extract_addr_range()) >= 0 && 8 main.c 242 (status = ()) >= 0) 9 main.c 244 (status = display_lines(current_addr, current_addr,
cscope-indexer
おまけの実験的なスクリプトが付属してた。これを夜中にcronで回しておくと、最新のインデックスが使えるそうだ。まあ、定期的にやってくる、ロボットみたいだな。
どんな挙動になるか -v をつけて確認。実際に使う時は、-r も付けてdirの中まで再帰すべきだ。
ob$ cscope-indexer -v Creating list of files to index ... Creating list of files to index ... done Indexing files ... Indexing files ... done
成果物は下記。気になるcscope.filesなんてのを確認。
ob$ ls -l cscope.* -rw-r--r-- 1 sakae sakae 48 Jul 28 07:20 cscope.files -rw-r--r-- 1 sakae sakae 178482 Jul 28 07:20 cscope.out ob$ cat cscope.files buf.c ed.h glbl.c io.c main.c re.c sub.c undo.c
どうやら、インデックスの元になったファイル名が列挙されてた。ならば、こういう使いかたも出来るな。
ob$ ctags `cat cscope.files` ob$ cat cscope.files | xargs ctags
vim軍は、cscopeとctagsの併用を勧めていた。両者似た者同士だけど、元ネタのインデックスが違う。齟齬があるとまずいので、cscopeに合わせてctagsしたよって亊だ。
上記のいきなりctagsの場合は、巨大なファイルを扱かう場合、文句を言われるかも知れない。そんな時は、xargsを使えばよい。久し振りにxargsを思い出したぞ。
ああ、cscopeの対象リストは下記のように抽出してたぞ
( if [ "X$RECURSE" = "X" ] then # Ugly, inefficient, but it works. for f in * do echo "$DIR/$f" done else find $DIR \( -type f -o -type l \) fi ) | \ egrep -i '\.([chly](xx|pp)*|cc|hh)$' | \ sed -e '/\/CVS\//d' -e '/\/RCS\//d' -e 's/^\.\///' | \ sort | \ sed -e '/[ \t]/s/^.*$/\"&\"/' > $LIST_FILE
古いレビジョン管理ソフトのCVSやRCSを除けるようにしてる所に、歴史を感じますなあ。今の人はgitしか知らないだろうからね。
xcscope
このcscopeをemacsから使えないか? 勿論使える。cscopeのソースに付属してるし、emacsのパッケージ集積城にも勿論登録されてる。
で、インストールして、キーバインドが使えるように、(cscope-setup) をinit.elに追加した。ネットを探ってもこれに言及されていないので、オイラーの所だけの特殊事情なんだろうか?
trace ex for tag
main.c: unmodified: line 1395 :tag append_lines :.-2,.+2p single period is read or EOF; return status */ static int append_lines(int n) { int l;
最初に ex main.c しといてから、tagサーチ。ちゃんと移動したか確認。問題無し。その時の動きをgdbで追跡
(gdb) b binary_search Breakpoint 1 at 0x1430d50f: file ../ex/ex_tag.c, line 1190. (gdb) c Continuing. Breakpoint 1, binary_search (string=0x44564200 "append_lines", front=0x3cfa8000\ "GET_COMMAND_SUFFIX\tmain.c\t/^#define GET_COMMAND_SUFFIX() \\\\$/\nGET_THIRD_\ ADDR\tmain.c\t/^#define GET_THIRD_ADDR(addr) \\\\$/\nMUST_BE_FIRST\tmain.c\t/^#\ define MUST_BE_FIRST() \\\\$/\nMmain\tmain.c\t/^main(volatile"..., back=0x3cfa8\ e62 "") at ../ex/ex_tag.c:1190 1190 p = front + (back - front) / 2;
呼出履歴。
(gdb) bt #0 binary_search (string=0x44564200 "append_lines", front=0x3cfa8000 "GET_COMM\ AND_SUFFIX\tmain.c\t/^#define GET_COMMAND_SUFFIX() \\\\$/\nGET_THIRD_ADDR\tmain\ .c\t/^#define GET_THIRD_ADDR(addr) \\\\$/\nMUST_BE_FIRST\tmain.c\t/^#define MUS\ T_BE_FIRST() \\\\$/\nMmain\tmain.c\t/^main(volatile"..., back=0x3cfa8e62 "") at\ ../ex/ex_tag.c:1190 #1 0x1430ce2f in ctag_sfile (sp=0x44599800, tfp=0x44570a20, tqp=0x44586a80, tn\ ame=0x44564200 "append_lines") at ../ex/ex_tag.c:1017 #2 0x1430af95 in ctag_slist (sp=0x44599800, tag=0x44564200 "append_lines") at \ ../ex/ex_tag.c:953 #3 0x1430ab1c in ex_tag_push (sp=0x44599800, cmdp=0x4459e7c8) at ../ex/ex_tag.\ c:128 #4 0x142f31e7 in ex_cmd (sp=0x44599800) at ../ex/ex.c:1371 #5 0x142efde9 in ex (spp=0xcf7eb640) at ../ex/ex.c:128 #6 0x1431a91b in editor (gp=0x4459e760, argc=1, argv=0xcf7eb808) at ../common/\ main.c:429 #7 0x142ead88 in main (argc=2, argv=0xcf7eb804) at ../cl/cl_main.c:97
tagに無いhogefugaを検索。
(gdb) p front $3 = 0x749e9778 "get_tty_line\tio.c\t/^get_tty_line(void)$/\nhandle_hup\tmain.c\ \t/^handle_hup(int signo)$/\nhandle_int\tmain.c\t/^handle_int(int signo)$/\nhan\ dle_winch\tmain.c\t/^handle_winch(int signo)$/\nhas_trailing_escape\tmai"... (gdb) p front $4 = 0x0
上はバイナリーサーチの結果、下はリニアサーチの結果。まて、コードをじっくり眺めると
if (fstat(fd, &sb) != 0 || (map = mmap(NULL, (size_t)sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, (off_t)0)) == MAP_FAILED) { tfp->errnum = errno; (void)close(fd); return (1); } front = map; back = front + sb.st_size; front = binary_search(tname, front, back); front = linear_search(tname, front, back); if (front == NULL) goto done;
リニアサーチする時の引数に、バイナリーサーチの結果をフィードバックしているね。こうして、リニアサーチの検索エリアを狭めているのか。 ああ、コードをざっと見、mmapでメモリー上に割付られたtagsファイルのfrontからbackの範囲内で、与えられた文字列を検索しろって亊だった。
tagsファイルは整列されてるから、tag文字が有れば発見出来る。発見したアドレス以降で、今度はリニアサーチ。一発で見付かるって寸法だな。
まて、 カーネルのtagsを作る時、わざわざtagsファイルをsortしてた。ctagsでも再帰した部分を含めてのsortはやってくれないのかな。だから、外部でソートしてる(本当か要確認)。
じゃ、行儀の惡いtagsファイル(否sort)がやってきた時の挙動を調べる必要が有るな。
ファイルのシャッフル
整列されてるtagsファイルをシャッフルしたいぞ。どんな方法が有るか? rubyで一行野郎して、御満悦な人やら、pythonでしょって人やら、楽しい分野みたい。 渋くやるなら、シェルでshufコマンドを使って入力情報をいろんな方法でシャッフルしてみるとかが紹介されてた。でも、リナ限定でしょ。こちとらOpenBSDの住人であるます。shufなんてコマンドは有りません。
整列用のコマンドは、sortだ。unixの直交政治からいって、ランダム化する機能もきっとsortに組込まれているに違いない。
-R, --random-sort, --sort=random Sort lines in random order. This is a random permutation of the inputs with the exception that equal keys sort together. It is implemented by hashing the input keys and sorting the hash values. The hash function is randomized with data from arc4random_buf(3), or by file content if one is specified via --random-source. If multiple sort fields are specified, the same random hash function is used for all of them. -r, --reverse Sort in reverse order.
ほら、有ったね。キーはOpenBSDが得意とする乱数発生器arc4randomを使ってますとな。確かに、sort -R tagsの結果を眺めてみると、実行の度に行の並びがバラバラに出力された。このオプション使えるね。
まて、試験するなら、不確定要素も持ち込むなが鉄則。折角見付たオプションだけど使用を辞退しましょ。その代わりに、-r を使っておこう。組込まれているバイナリーサーチは昇順されてる亊を仮定してる。そこに降順のデータを与えるのは、有りの状況だろう。
取り敢えず、下記のようにして、試験用のtagsファイルを作成。67エントリーのタグが有った。
vbox$ ctags *.[ch] vbox$ sort -r tags > z; mv z tags vbox$ head -3 tags write_stream io.c /^write_stream(FILE *fp, int n, int m)$/ write_file io.c /^write_file(char *fn, char *mode, int n, int m)$/ unset_active_nodes glbl.c /^unset_active_nodes(line_t *np, line_t *mp)$/
実際に走らせてみると、リニアーサーチ内で、直にreturnしてしまう。
(gdb) s linear_search (string=0x7f05d270 "Mmain", front=0x4753c000 "write_stream\tio.c\\ t/^write_stream(FILE *fp, int n, int m)$/\nwrite_file\tio.c\t/^write_file(char \ *fn, char *mode, int n, int m)$/\nunset_active_nodes\tglbl.c\t/^unset_active_no\ des(line_t *np, line_t *mp)$/\nu"..., back=0x4753ce62 "") at ../ex/ex_tag.c:121\ 8 1218 while (front < back) { (gdb) n 1219 switch (compare(string, front, back)) { (gdb) 1223 return (NULL);
実質、用をなさない、ファイクなコードでした。
linear_search(char *string, char *front, char *back) { while (front < back) { switch (compare(string, front, back)) { case EQUAL: /* Found it. */ return (front); case LESS: /* No such string. */ => return (NULL); case GREATER: /* Keep going. */ break; } SKIP_PAST_NEWLINE(front, back); } return (NULL); }
EQUALだけを確認すべしだな。まあ、現状の仕様だと、tagsファイルは昇順にソートされている亊って亊だな。これが守られないと、Mmain: tag not found と誤った結果になってしまう。
なお、気付いた亊が一つある。それは、mainってタグだけが特別扱いされてるって亊。Mmainが正解。そんな亊、知らない仕様だ。やっぱりmainだけは、エントリーポイントになるんで、特別扱いしたかったんです、ってctagsの作者様の気持をくんで上げましょう。
平均血圧
前回ちょっと気になった平均血圧の亊、病院へ行ったついでに、看護師さんに聞いてみた。あんちょこを取出して、教えてくれたよ。
(最高血圧 - 最低血圧) / 3 + 最低血圧
という式で計算するそうだ。何で最初からぐぐるしなかった? 思考停止してたんだな。 血 圧について なんてのが、沢山出てきた。
ちょっと悔しいので、 何で3でわるの? なんていう問いをたててみた。
なんか学会が、病人を作ってサステナブルに儲かるようにしてんじゃなかろうか。式を勝手に捻り出していないか?
いや、元電気屋なんで、血圧を刻々と変化する波として考えてみる。直流に重畳した交流って亊ね。瞬間的な血圧は、最低血圧に変動分を加えたものになる。変動分ってのは、最高血圧 - 最低血圧の間に存在す交流成分。周波数に相当するのは、脈拍だな。
この変動分を、三角波とか、のこぎり波って考えればよい。単純に三角波としたら、その面積は、 高さに相当する、血圧差と底辺に相当する周期、それをかけ算して2で割ればよい。
周期は面倒なので1秒(60脈拍/分)とすれば、変動分の面積は、血圧差 / 2 となる。学会の式は3で割ってる。そうか、もうすこし尖っているから、それを考慮してるのか。
脈拍は無関係なのか。曰く、平常脈拍60だったのが、運動したら120になりましたって場合。 上で底辺を勝手に1って決めた、それが60拍相当だったとしたら、脈拍120の場合は、底辺が 1/2 になる。でも、その代わりに波が2つ分になるんで、全体としては同じ亊。ゆえに、脈拍は考慮しなくても良いって亊だな。
病院にある血圧計は、平均血圧も出てくるんだけど、上の式より大分大目に表示される。盛って、病人を作る仕様に改造してあるんだな。