先日。
Raspberry Pi 上の clang のバグっぽい挙動に遭遇したので報告。
現象
三角関数の計算を間違える。
環境
$ uname -a
Linux raspberrypi 4.19.50-v7+ #896 SMP Thu Jun 20 16:11:44 BST 2019 armv7l GNU/Linux
$ cat /etc/debian_version
10.0
$ clang --version
clang version 7.0.1-8+rpi1 (tags/RELEASE_701/final)
Target: armv6k-unknown-linux-gnueabihf
Thread model: posix
InstalledDir: /usr/bin
$ apt info clang
Package: clang
Version: 1:7.0-47
Priority: optional
Section: devel
Source: llvm-defaults (0.47)
Maintainer: LLVM Packaging Team <pkg-llvm-team@lists.alioth.debian.org>
Installed-Size: 23.6 kB
Depends: clang-7 (>= 7~)
Breaks: clang-3.2, clang-3.3, clang-3.4 (<< 1:3.4.2-7~exp1), clang-3.5 (<< 1:3.5~+rc1-3~exp1)
Replaces: clang (<< 3.2-1~exp2), clang-3.2, clang-3.3, clang-3.4 (<< 1:3.4.2-7~exp1), clang-3.5 (<< 1:3.5~+rc1-3~exp1)
Download-Size: 7,468 B
APT-Manual-Installed: yes
APT-Sources: http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages
Description: C, C++ and Objective-C compiler (LLVM based)
Clang project is a C, C++, Objective C and Objective C++ front-end
for the LLVM compiler. Its goal is to offer a replacement to the GNU Compiler
Collection (GCC).
.
Clang implements all of the ISO C++ 1998, 11 and 14 standards and also
provides most of the support of C++17.
.
This is a dependency package providing the default clang compiler.
再現方法
まずはソースコード:
clangsin.cpp
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdint>
template< typename t >
void dump( char const * name, t * v )
{
auto p = reinterpret_cast<std::uint8_t const *>(v);
std::cout << name << "=";
for( auto it = p ; it != p+sizeof(*v) ; ++it ){
std::printf( "%02x ", *it );
}
std::cout << "\n";
}
int main()
{
float f = std::cos( 3.45f );
double d = std::cos( 3.45 );
std::cout << "f=" << f << " d=" << d << std::endl;
std::printf( "f=%g d=%g\n", f, d );
dump("f", &f);
dump("d", &d);
return 0;
}
そして実行結果:
$ clang++ -Wall clangsin.cpp && ./a.out
f=-9.32929e-17 d=2.11371e-314
f=3.45 d=6.20896e-312
f=cd cc 5c 40
d=9a 99 99 99 24 01 00 00
$ g++-8 -Wall clangsin.cpp && ./a.out
f=-0.952818 d=-0.952818
f=-0.952818 d=-0.952818
f=e5 eb 73 bf
d=98 e6 d6 9f 7c 7d ee bf
おかしなところ
計算結果
計算結果は、g++-8 のものが正しい。clang の結果は間違っている
ていうか。
f
の値なんて、絶対値が 1
を遥かに超えているし、入力の 3.45f
そのまんまだし、一体何なんだ。
float と double
float
と double
はほぼ同じ値になるべきだが、そうなっていない
printf と cout
printf
と cout
は同じ変数を参照しているはずなのに、まったく違う値を出している。困る。
ダンプの結果と整合するのは printf
の方である。
"cd cc 5c 40".split(" ").map{|e|e.to_i(16).chr}.join.unpack("f")
#=> [3.450000047683716]
"9a 99 99 99 24 01 00 00".split(" ").map{|e|e.to_i(16).chr}.join.unpack("d")
#=> [6.208959684366e-312]
原因
さっぱりわからない
対策
当面は Raspberry Pi 上で clang を使うのをやめることにした。