同名だが(違う場所にあって)異なるダイナミックリンク(共有)ライブラリの問題(適切な解決法を求む)

FreeBSDにおいて、プログラムの起動時に次のようなエラーで起動に失敗することがあります。

/lib/libgcc_s.so.1: version GCC_4.6.0 required by /usr/local/lib/gcc48/libgfortran.so.3 not found

GCCgcc-4.8 を使っている場合)

原因は、libgcc_s.so.1 として /usr/local/lib/gcc48/libgfortran.so.3 が本来期待している /usr/local/lib/gcc48/libgcc_s.so.1 ではなく、/lib/libgcc_s.so.1 をロードしてしまっていることにあります。

実行ファイルが libgfortran のみに依存していれば、libgfortran.so.3 に埋め込まれている依存性によって正しいライブラリが読み込まれます。

(参考)

$ ldd /usr/local/lib/gcc48/libgfortran.so.3
/usr/local/lib/gcc48/libgfortran.so.3:
	libquadmath.so.0 => /usr/local/lib/gcc48/libquadmath.so.0 (0x801717000)
	libm.so.5 => /lib/libm.so.5 (0x801952000)
	libgcc_s.so.1 => /usr/local/lib/gcc48/libgcc_s.so.1 (0x801b7b000)
	libc.so.7 => /lib/libc.so.7 (0x800821000)

しかし、実行ファイル自身が libgcc_s に依存している場合、通常の libgcc_s は /lib/libgcc_s.so.1 ですから、そちらへの依存が優先されてしまい、前述のようなエラーになります。以下のようにして再現できました。

$ cat sample.c
#include <stdio.h>

extern void *__deregister_frame;
extern void *_gfortran_matmul_l4;

int
main(void)
{
  printf("%p\n", __deregister_frame);
  printf("%p\n", _gfortran_matmul_l4);

  return 0;
}

$ cc sample.c -L/usr/local/lib/gcc48 -lgfortran

$ ldd ./a.out
./a.out:
	libgfortran.so.3 => /usr/local/lib/gcc48/libgfortran.so.3 (0x80081f000)
	libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x800b36000)
	libc.so.7 => /lib/libc.so.7 (0x800d44000)
	libquadmath.so.0 => /usr/local/lib/gcc48/libquadmath.so.0 (0x8010f0000)
	libm.so.5 => /lib/libm.so.5 (0x80132b000)

$ ./a.out
/lib/libgcc_s.so.1: version GCC_4.6.0 required by /usr/local/lib/gcc48/libgfortran.so.3 not found

一応は「混ぜるな危険」ということであるわけですが(ワークアラウンドとしては LD_LIBRARY_PATH=/usr/local/lib/gcc48 を付ければ一応は動く)、

しかし、可能であれば、それぞれの場所にあるライブラリが別々にロードされるようにすべきかと思います。が、可能でしょうか?

「ISLISPを使うべきでないたった1つの理由」に関して

「ISLISPを使うべきでないたった1つの理由」( http://d.hatena.ne.jp/Isuzu_T/20130623/1372003378 )が誤解している点について、簡単にまとめておこうと思います。

要点

上記はてなダイアリーから引用しますが、

マクロは,実行準備時に展開される,いかなる実行時情報も使えない.

仕様にあるこの一文が悲しみです.「実行時情報」が使えないということは,つまり,自分で定義した関数によるマクロの展開は行えない,ということです.なぜなら,関数が定義されるのは,実行時だからです.

ひとつめの引用の、規格票中の文は意訳などではなく、原文(英語)の仕様にもきっちり対応する文がありますので翻訳の問題などではありませんが、もしこのような誤解が多いようであれば削ったほうが良いような気もします。「実行準備」については仕様がある表現ですが、「実行時情報」(runtime information)という表現は仕様の中でここ以外には出てきません。

ユーザーが定義した関数をマクロの定義中で使うことの、このような視点(実行準備と実行)から見た可否については、類推っぽくなりますが、マクロの定義とその使用の関係から考えることができるでしょう。

マクロの展開は全て実行準備時に行われるわけですが、最上位のdefmacro形式によるマクロの定義は実行準備(時)ではなく、実行されて定義されるわけです。ですから、別の箇所でそのマクロが使用されて「実行準備時に展開され」る時に、そのマクロはそれ以前に「defmacro形式が実行されて、定義されたもの」ということになります。

同様にして、マクロの展開関数中で、それ以前にdefun形式により定義されている関数を使用することも問題ないと考えることができるでしょう。以下はこの話題に関するぐだぐだした話です。

その他

規格票中の最初の文と似たような表現が、PCL(『実践 Common Lisp』)中にあります。同書の §8.2 「マクロ展開時 vs. 実行時」に、

 マクロ展開時に動作するコードは実行時とはまったく異なる環境で動作するので、両者の違いを常にしっかりと区別することが大切だ。これはつまり、マクロ展開時は実行時に存在するデータにはアクセスできないってことでもある。(後略)

参考のため原文も見ておくと、

It's important to keep this distinction firmly in mind because code running at macro expansion time runs in a very different environment than code running at runtime. Namely, at macro expansion time, there's no way to access the data that will exist at runtime. (後略)

http://www.gigamonkeys.com/book/macros-defining-your-own.html

ここで言っている「実行時」というのは、そのコード片(式)を含んでいる関数が実引数に適用され評価される時、という意味であって、「実行時に存在するデータ」(the data that will exist at runtime)というのは、式中にあらわれる仮引数の値、といったようなものを指しており、Lispプログラマの常識的にいってごくあたりまえのことを言っているに過ぎません。

なぜほぼ同様の表現なのに、ISLISPの規格票の解釈では、前述のような誤解をもたらしたか、ということを考えるに、おそらくISLISPのミニマリズムに起因する実行モデルの不在ではないかと思います。以下で説明します。

JISの規格票では §1.1 の「適用範囲」の b) 適用外事項 の 3) に

ISLISPテキストを実行準備する方法,及び実行のために準備されたISLISPテキストを起動する方法。

とあり、実行準備→実行というフェーズがどう(いかにして)進行するのか、という点の詳述が範囲外となっています。

そのため、それについての記述は、§1.3 の「オブジェクトは、実行のために準備される (prepared for execution) 。」から始まる段落で述べられている以外には、まとまって存在していませんが、これが原因ではないでしょうか。

ここで、冒頭が「オブジェクトは、」となっていることに注意が必要かと思います。これがもし「ISLISPテキストは、」となっていたら、プログラム全体がまずいっぺんに実行準備され、そして実行される、という意味になるでしょう(つまり、冒頭で引用したような、マクロ中でユーザーが定義した関数が使えない、と考えてしまうことにつながります)。しかし、「オブジェクトは、」となっていますから、ISLISPの「テキスト」(§1.7.37を参照)を構成する個々の「最上位形式」(§1.7.38を参照)について述べているのであって、「最上位形式の並び」は(仕様上は)オブジェクトにはなりませんから、「プログラム全体がまずいっぺんに実行準備され」という解釈は妥当ではない、ということになります。

そういうわけで、仕様では(それぞれの最上位形式に対応する)オブジェクトについて「実行準備され、実行される」ということのみが述べられているということは確認できたとしてよいと思いますが、最後にもう少し、マクロについて考えます。

規格票中の 8. マクロ には、その順序として「マクロは,実行準備の段階で,それを使用する前に定義しなければならない。」とありますが、もしこれに加えるなら、「展開関数中で使用する関数も、そのマクロを使用する前に定義しなければならない。」ということになるかと思います。(あるいはコンパイルの都合を考えると、マクロ定義より前に定義を必須としたほうが良い?)

crubyのFloatにFast inverse square rootを(モンキーパッチで)追加する話

Fast inverse square root自体については「30のプログラミング言語でFast inverse square rootを実装してみました!」( http://itchyny.hatenablog.com/entry/2016/07/25/100000 )を参照してください。

せっかくの高速な手法ですから、高速な実装を考えてみます。Rubyの場合、まっとうに実装するのであれば Math モジュールに追加するべきですが、性能のことを考えると関与するオブジェクトが少ないほうが良いですから、Float クラスにモンキーパッチで追加することにしました。

こんな感じになります。

#include <stdint.h>
#include <float.h>
#include "ruby.h"

static VALUE
fast_inv_sqrt(VALUE v)
{
  double d = RFLOAT_VALUE(v);
  if ((d > 0.0) && (d <= DBL_MAX)) {
    //NOP
  } else {
    rb_raise(rb_eFloatDomainError, "out of domain");
  }
  union u_di {
    double d;
    uint64_t i;
  } d_i;
  d_i.d = d;
  d_i.i = 0x5fe6eb50c7b537a8ULL - (d_i.i >> 1);
  double d2 = d / 2.0;
  double g = d_i.d;
  d_i.d = g * (1.5 - d2*g*g);
#if 0
  d_i.i += 0x4e1c39a47a8ULL;
  g = d_i.d;
  d_i.d = g * (1.5 - d2*g*g);
  d_i.i += 0x14b9e8a78ULL;
#endif
  g = d_i.d;
  return DBL2NUM(g);
}

void
Init_fisqrt(void)
{
  rb_define_method(rb_cFloat, "fast_inv_sqrt", fast_inv_sqrt, 0);
}

ポイントとなる点をいくつか説明してゆきます。

まず Init_fisqrt が拡張ライブラリのエントリポイントで、これは見たままかと思います。

関数 fast_inv_sqrt が本体で、最初と最後にある VALUE と double の相互変換は拡張ライブラリの書き方の定番通りです。

続いて引数の範囲チェックですが、浮動小数点数のチェックは「真になる条件」でチェックするのがセオリーです(比較に NaN が関わるると偽になるため)。

ビットパターンを保存した浮動小数点数と整数の変換に union を使っているのも、この手のトリックの定番と言っていいでしょう(標準において、未定義ではなく処理系定義のため、気休め程度だがマシ)。

単精度の時の 0x5f3759df に相当するマジックナンバーは、妥当と思われる方法で私が探索(詳細は略)したものです。

#if 0 でコメントアウトしてある部分は、せっかくなので高精度化を図ってみたコードですが、これがあると **(-0.5) で正確な値を計算するよりも遅くなってしまったのでコメントアウトしました。単にニュートン法をもう1回繰返すだけではなく、誤差で必ず負の側に予測可能な範囲でズレることがわかっているので、それを調整する加算も入れてあります。

続いてベンチマークに使ったスクリプトを示します。

#! /usr/local/bin/ruby23

require 'benchmark'

require_relative 'fisqrt'

a = 1.0

result = Benchmark.realtime {
  (0..10000000).each {|i|
    a.fast_inv_sqrt
    a.fast_inv_sqrt
    a.fast_inv_sqrt
    a.fast_inv_sqrt
    a.fast_inv_sqrt
    a.fast_inv_sqrt
    a.fast_inv_sqrt
    a.fast_inv_sqrt
    a.fast_inv_sqrt
    a.fast_inv_sqrt
  }
}
print "result: #{result}s\n"

result = Benchmark.realtime {
  (0..10000000).each {|i|
    a**(-0.5)
    a**(-0.5)
    a**(-0.5)
    a**(-0.5)
    a**(-0.5)
    a**(-0.5)
    a**(-0.5)
    a**(-0.5)
    a**(-0.5)
    a**(-0.5)
  }
}
print "result: #{result}s\n"

result = Benchmark.realtime {
  (0..10000000).each {|i|
    1.0 / Math.sqrt(a)
    1.0 / Math.sqrt(a)
    1.0 / Math.sqrt(a)
    1.0 / Math.sqrt(a)
    1.0 / Math.sqrt(a)
    1.0 / Math.sqrt(a)
    1.0 / Math.sqrt(a)
    1.0 / Math.sqrt(a)
    1.0 / Math.sqrt(a)
    1.0 / Math.sqrt(a)
  }
}
print "result: #{result}s\n"

次のようになります。わずかですが速いという結果が出ています。

result: 6.402902246918529s
result: 7.31780265388079s
result: 9.100973834982142s

4004のブートストラップキャパシタ

この記事で言及する「ブートストラップ」は、電気(電子)回路の技法のそれであり、コンピュータの電源投入時やリセット時などの起動シーケンスのことではありません。

(回路技法の)ブートストラップとは

既にご存じの方は飛ばしてください。

以下の2つの回路図は、『定本 トランジスタ回路の設計』(ISBN:9784789830485)の、第8章の 図2 と 図21 ですが、


赤い線で囲んだ部分に注目すると、1つめの回路ではグランド(0V)が基準となって動作する部分が、2つめの回路では自分自身の動作によって電位が決まる部分が基準になって動作するようになっています。

このように「自分自身の動作を利用して、動作電位が決まるような、電気(電子)回路の技法」は「ブートストラップ」と呼ばれています。語源はコンピュータの起動時の動作を指すそれとほぼ同じと思われますが、コンピュータのほうはプログラム内蔵方式のコンピュータができた戦後の頃にできた言葉であるのがほぼ確実であるのに対し、こちらはどうも戦時中(真空管回路)に、おそらくレーダーの研究開発などといったような秘密の下で考案されたものではないだろうかと思うのですが、由来を先日ざっと追ってみたものの、よくわかりませんでした。*1

最初に示した例はカスコード(cascode)方式の増幅回路のベース-エミッタ間の電位差を一定にするものでしたが、他に、ブートストラップの技法が使われる例としては、スイッチング電源のハイサイドがあります。

パワーMOSFETを電源などドライバ回路に使う場合、グランド側はNチャネルMOSFETを使えば、ゲート電圧が Vdd に近ければオン、グランド(Vss)に近ければオフ、という動作になるのでそれで良いわけですが、ハイサイド(電源側、Vdd 側)をそれと対称に構成しようとすると、PチャネルMOSFETが必要になります。しかし、Pチャネルは良い特性があまり得られず、品種も少ないですから、ハイサイドもNチャネルMOSFETで構成するわけですが、そうするとそのFETのソースの電位が Vdd に近くなっても十分に駆動するには、ゲートを駆動する電圧について Vdd + 2V~3V 程度のゲタを履かせる必要があります。

MOSFET のゲートですから、電流(電力)はたいして必要ないので、簡単なDCDCコンバータで電圧を作ったりするわけですが(『定本 続 トランジスタ回路の設計』の第10章に例があります)、スイッチング電源の場合は常に矩形波でパタパタしている電力を扱うわけですから、それをうまくキャパシタで利用してやる方法があります。

電源用モジュールの製品などで、外付け部品としてキャパシタが必要なものがありますが(ロームによるスイッチングレギュレータの解説 http://micro.rohm.com/jp/techweb/knowledge/dcdc/dcdc_sr/dcdc_sr01/829 や、TIによる降圧型スイッチングDCDCコンバータの解説 http://www.tij.co.jp/analog/jp/docs/analogsplash.tsp?contentId=54765 を参照)、そのキャパシタは「0V <=> Vdd」の矩形波を利用して「Vdd <=> Vdd+α」というような電圧を作ってやるのに使われているわけです。

1970年代のMOSプロセス

21世紀の現代ではもっぱらCMOSが使われているわけですが、1970年代~1980年代、なじみのある製品でいうと電卓戦争の時代から8~16ビットマイクロプロセッサの時代は、初期のメタル1層から2層へ、ロジックも PMOS → NMOS → CMOS と変遷があり、表向きにはスペックの向上として現れていますが、その裏にはいくつかのプロセスにおける変革があります(嶋さんによるこちらのコラム http://itpro.nikkeibp.co.jp/article/Watcher/20060323/233069/ が具体例に詳しい証言になっている)。

インテル4004(以下、ICの名前は単に4004等と呼ぶ)では、まだPMOSの時代で、しかもイオン注入によって部分的にディプリーション(ノーマリーオン)のMOSFETを作ることができるようになったのはもっと後であり(前述の嶋さんのコラムを参照。8080でもNMOSになっただけであり、イオン注入はZ80で採用された)*2、ブートストラップ方式によるちょっとしたトリックのような回路が使われています。

4004のブートストラップキャパシタ

4004では負電源とPMOSだったわけですが、それでは慣れない我々には少々非直感的なので、以下では正電源・NMOSで考えることにします。

相補型(CMOS)でないMOSで一般的な論理方式は ratioed logic と呼ばれるもので、NMOSの場合はハイサイドに小さめのトランジスタを置いて、プルアップする能動負荷とし、反対側に大きめのトランジスタでnotやnandやnorといった論理を作るものになります。

こんな感じです。上の能動負荷となっているFETについてですが、ディプリーション型であればゲートはソースかグランドに直結するわけですが、ここではエンハンスメント型ですから Vdd に直結されます。すると、出力が Low の時はロジック側の大きなトランジスタで引き下げられるわけですから問題ないわけですが、出力が High の時のプルアップが問題で、Low の時の電圧が上がりすぎないように小さめのトランジスタで駆動している上に、ゲート-ソース間の電圧として Vth 程度の電圧が必要ですから、Vdd まで出力を引き上げることができない、いわゆるフルスイングでない出力ということになってしまいます。

それでも問題ないように論理を工夫したりする方法もあるわけですが、4004では、以下で説明するようなちょっとトリックっぽいブートストラップの手法で、一時的に電源を越えるような電位を作って問題を回避しています。

4004の回路図は3枚に分かれていますが、そのうちの1枚「4004 ADDRESS REGISTER, INCREMENTER AND INDEX」というタイトルの図の片隅に、次のような注記があります。

ここで重要なのは下の2つで、プルアップ抵抗のように描かれているのは、実際にはMOSFETによる能動負荷だよ、ということを示すものです。上にあるほうは前述のような、単純にゲートをドレインに短絡したFETですが、トリックがあるのは下のFET2個とキャパシタを組み合わせたものです。「B」という記号は「ブートストラップ」の意でしょう。

この信号は時分割のバスなど、常に(矩形波による)オンオフがある信号であることが前提です。4004はレジスタに静的ではない回路を使っているため、動作をハードウェア的に完全に止めてしまうことはできない、完全には静的でない論理回路ですが、(実は)この部分も完全に静的ではなくある程度の動作が常に必要です。

まず、出力が Low で定常的だとする所から始めます。上のFETにより下のFETのゲートは Vdd-Vth 程度の電位になっています。出力は Low で、下のFETのゲート-ソース間電圧は十分にありますから、下のFETもオンになっていますが、前述のように ratioed logic のためにロジック側で出力は Low に引き下げられている、というような状態になっています。キャパシタがあるわけですが、ICの中に作れる程度ですから、定常状態で放置されれば電荷はそう長くは保ちません。

次に、ロジックの入力が変化して、出力が High に変化し始めた、とします。するとキャパシタが、いわゆる「スピードアップコンデンサ」のそれと似たような働きをすることになって、上のFETのソース=下のFETのゲートの電位が、出力電圧の変化に合わせて上がってゆき、2*Vdd-Vth 程度まで上がることになります。これにより下のFETがオンに保たれるため、普通であれば Vdd まで上がらないはずの出力が、Vdd まで上がります。

また、上のFETはゲート電圧よりもソース電圧のほうが高いため、オフ状態になります。

(普通のディスクリートMOSFETで似たような回路を作ろうとした場合、ソース電極がサブストレート(バルク)にも接続されていて寄生ダイオードが存在するため(よく使われる右のような記号はそれを表現したものです)、ソースの電位をドレインより上げても電荷が抜けていってしまいますが、ICの中ではソースとサブストレートを別にすることができます)

以上のようにして、4004ではブートストラップの手法により、動的な一部の信号線の( High への)駆動力が強化されています。

実装

マスクパターンでは、以上で説明したキャパシタが、余計な面積を必要としないように巧妙に形成されているはずです(が、力不足で説明できる所まで理解できていません)。

文献

嶋さんの本、

マイクロコンピュータの誕生―わが青春の4004

マイクロコンピュータの誕生―わが青春の4004

には、この手法に関して直接的な言及はありません。嶋さんは4004チップに関して論理設計だけでなく回路やマスクの作業もやっておられますから、それ自体については承知のはずですが、おそらく、フェデリコ・ファジンさんの功績であることから(自分のそれと混同されることを避けるために)言及しなかったのかもしれません。Z80においてイオン注入法を採用したことで、ディプリーション負荷FETが使えるようになった、という間接的言及といえる記述はあります(イオン注入法がデッドコピー対策のトラップのためにも使われた、という記述も興味深い所です)。

近年出たドキュメンタリー、

インテル 世界で最も重要な会社の産業史

インテル 世界で最も重要な会社の産業史

には、次のような記述があります( p. 183 )。

このなかでいわば「副産物」*3のように生まれた発明が、やがて半導体史上シリコンゲートと並ぶ意義を持つことになった。ファジンは個々のゲートを、相方となるトランジスタの上側にブートストラップしたのだ。それまで不可能と思われていたことである。この手法はすぐに普及し、それから四〇年にわたってほぼすべての種類のチップに利用された。(この段落後略)

というようにあるのですが、ここまでで説明したように4004で使われたブートストラップは、イオン注入法によるディプリーション負荷FETが使えるようになるまでの「つなぎ」的な色の濃い手法であり、CMOSになってからは忘れられたような手法ではないかと思いますので、何か違う感じもします。もしかしたら翻訳の際の影響かもしれませんが、もうひとつの鍵となった技術である buried contact が関係あるかもしれません。

なお同書は、(『電子立国』ではあまり語られなかったため、日本などではあまり知られていない)当時の、また他の多くの時代のインテルの内情が書かれており、「マイクロプロセッサは誰の功績か」などといった話題についても(他社への言及が無い点を除けば)フェアかつ背景に踏み込んだ記述もあり、必読の1冊ではないかと思います。

*1:1955年に出願された特許の中に出てくるのが確認できるのだが、あたりまえの技術として言及されているように見える https://www.google.com/patents/US2850629

*2:4004の回路の素子について、デプレッション型、と言及している記事があるが http://www.atmarkit.co.jp/fsys/zunouhoudan/139zunou/4004_40thanv.html 誤解ではないかと思われる。

*3:原文では傍点

「ゲーム性」という語の(もしかしたら最古の)用例


ここにスキャンして載せたのは、「物理の散歩道」シリーズという単行本のタイトルで知られる、『自然』誌の「ロゲルギスト」による連載エッセイの一部で、同誌19巻6号(1964年6月号)「コントロールを楽しむゲーム」、筆者はロゲルギスト I2今井功先生)からのものです(72ページ)。その時期から、「ゲーム性」という語のかなり古い、もしかしたら最古の用例とも思われます。
おもちゃの話とゲームの話がないまぜになっていますが、おもちゃのうちでも、完全に偶然に任せられるのでもなく、完全に人間がコントロールするのでもなく、競技(英語 game の原義のひとつに近い)的な性格等を持っている、といったような意味、すなわち、後によく使われるようになったのとだいたい似たような意味で使われていることがわかるかと思います(なお、内容を確認されたい方は、雑誌のバックナンバーでなくとも、『第三 物理の散歩道』に再録されていますので、そちらの92ページを参照されれば良いでしょう)。

物理の散歩道 第3 (科学ライブラリー)

物理の散歩道 第3 (科学ライブラリー)

情報処理学会発足の頃の話

これはハードコピーを見せたほうがインパクトがある、だろうと判断して持っていったところ、興味を持っていただけたのですが、


この「情報処理学会の発足は1960年、昭和でいうと35年」というのは、電気系6学会あたりに居る人でも(最近は? あるいは情報処理以外の所属だと)あまり知られてないようで、そのあたりの情報へのポインタとかを書いてみようと思います。

創設秘話、といったようなものは(某学SF研の創設の言葉は「闇あれ」だったと伝え聞いておりますが…脱線)、後々になってから面白い話が出てきたりもするものですが、情報処理学会の場合は古いほうに興味深いものがあり、現在「50年史」の附属資料として配布されている「学会30年のあゆみ」中の「30年の軌跡」の冒頭部分をまず読んでみるのが良いように思われます。

(PDF) http://www.ipsj.or.jp/50anv/50nenshi/data/pdf/0101.pdf (PDF)

そこに「発足 情報処理学会は事実上,山下英男(所属:略),和田弘(所属:略)によって創設された.」と端的に書かれていますように(所属については当該2次文献執筆時のものであるため略した)、先見的なヴィジョンを持った少数のリーダーシップにより設立されたというように伺えます。

両先生については、情報処理学会のコンピュータ博物館(バーチャル博物館)にある「日本のコンピュータパイオニア」にある記事も参考になるでしょう( http://museum.ipsj.or.jp/pioneer/h-yama.html http://museum.ipsj.or.jp/pioneer/h-wada.html )。

また、2010年に『情報処理』に掲載された和田弘先生のインタビュー(インタビューは2004年 http://id.nii.ac.jp/1001/00069850/ )も参考になると思います。これはもうほんとに『電子立国』の世界で、あと、アスキーから出ていた本『計算機屋かく戦えり』にもインタビューが収録されていますが、そちらについては電子化という噂を聞いたような気もしますがどうなっているのかな……