LoginSignup
21
11
100万人に伝えたい!失敗を乗り超えた話を共有しよう

AtCoderのC言語で標準数学関数が使えなくなるようなので、x87を使えるようにしておく

Posted at

改悪される実行環境

2023年8月6日(日)、AtCoderで新ジャッジのテストコンテストが開催された。

新ジャッジテストコンテスト -Algorithm- - AtCoder
新ジャッジテストコンテスト -Heuristic- - AtCoder

これのHeuristicで sqrt 関数を使おうとした所、コンパイルエラーになった。
コードテストで発見したのでこれの提出リンクは無いが、Algorithmでも再現した。

提出 #44342804 - 新ジャッジテストコンテスト -Algorithm-

/usr/bin/ld: /tmp/ccQQlh1z.o: in function `main':
Main.c:(.text.startup+0x68): undefined reference to `sqrt'
/usr/bin/ld: Main.c:(.text.startup+0x88): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status

過去の問題では普通に sqrt 関数を使えているので、新仕様での改悪で間違い無さそうだ。

提出 #33735452 - デンソークリエイトプログラミングコンテスト2022(AtCoder Beginner Contest 239)

質問を投げようかとも思ったが、よく見ると

バージョンやライブラリなどに関する要望の受付は終了いたしましたので、お答え出来ません。

トップの注意事項で明示されている。
残念だなあ。

後の祭り

2023年3月~7月にかけて、言語の要望が募集されていた。

Language Test 202301 - AtCoder

今回の件を受けて確認すると、ここでもコンパイルエラーが再現した。

提出 #44347622 - Language Test 202301

とくに言語を追加してほしいという希望はなかったのであまり気にとめていなかったが、今思えばちゃんと確認しておくべきだった。

対策

標準ライブラリの数学関数 (たとえば sincossqrtatan2 などは使いたくなる機会がありそう) は使えなくなってしまうようだが、多くのx86環境ではx87という浮動小数点計算機能がある。
これを使うことで、標準ライブラリに頼らず、かつ自前での実装もせずに数学関数を使うことができる。

たとえば以下のサイトが役立ちそうである。

基本的には、以下の流れで数学関数を用いることができる。

  1. FLD命令で引数をメモリからx87のスタックにコピーする
  2. x87のスタック上で数学関数の計算を行う
  3. FSTP命令で計算結果をx87のスタックからメモリに転送する

数学関数の計算は、以下の命令で行うことができる。

実際に組み込んでみた。

double x87_sin(double angle) {
	double res;
	__asm__ __volatile__(
		"fldl %1\n\t"
		"fsin\n\t"
		"fstpl %0\n\t"
	: "=m"(res) : "m"(angle));
	return res;
}

double x87_cos(double angle) {
	double res;
	__asm__ __volatile__(
		"fldl %1\n\t"
		"fcos\n\t"
		"fstpl %0\n\t"
	: "=m"(res) : "m"(angle));
	return res;
}

void x87_sincos(double* sin_res, double* cos_res, double angle) {
	__asm__ __volatile__(
		"fldl %2\n\t"
		"fsincos\n\t"
		"fstpl %1\n\t"
		"fstpl %0\n\t"
	: "=m"(*sin_res), "=m"(*cos_res) : "m"(angle));
}

double x87_sqrt(double value) {
	double res;
	__asm__ __volatile__(
		"fldl %1\n\t"
		"fsqrt\n\t"
		"fstpl %0\n\t"
	: "=m"(res) : "m"(value));
	return res;
}

double x87_atan2(double y, double x) {
	double res;
	__asm__ __volatile__(
		"fldl %1\n\t"
		"fldl %2\n\t"
		"fpatan\n\t"
		"fstpl %0\n\t"
	: "=m"(res) : "m"(y), "m"(x));
	return res;
}

この x87_sqrt 関数は、新環境でも使えるようである。

提出 #44348412 - 新ジャッジテストコンテスト -Algorithm-

また、旧環境ではあるが、sincossqrtatan2 関数を用いている以前の提出

提出 #24617122 - 競プロ典型 90 問

の数学関数を今回用意した関数に置き換えても、正解になった。

提出 #44348463 - 競プロ典型 90 問

免責

最低限の動作確認は行ったが、今回用意した関数が正しく動作する保証はできない。
さらに、AtCoderのルールやLanguage Testのスプレッドシートを確認したが、CPUにx86が使われるという保証は発見できなかった。
x86でないCPUが使われた場合、今回用意した関数は利用できなくなる可能性が高いと思われる。
(エミュレーションなどが行われる可能性もあるため、利用できないと断言はできない)
今回用意した関数を使用した結果、コンテストにおけるペナルティやタイムロスなどの不利益、またはその他の損害が発生しても、筆者は責任を負わない。
使用する場合は自己責任でお願いする。

教訓

次に言語のアップデートがあるときは、ちゃんと確認しよう。
今回、今までgccとclangの2種類あったC言語がgccだけに減らされているし、放置すると次は0種類にされるかもしれない…

21
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
11