LoginSignup
149
71

More than 3 years have passed since last update.

その「0」は何進数ですか?

Last updated at Posted at 2021-03-03

十進数だろ JK

はじめに

C/C++ で 0 と書くと八進数として解釈されるため、十進数のゼロを書くことはできないという小ネタがありますが、では他の言語ではどうだろうと気になりうっかり調べてしまったので記事にしました。
まあ八進数だろうが十進数だろうが処理系の気持の話でしかなく何かが変わるというものでもありませんが……

結果

概要

大まかに以下のグループに分けられました。

  • 八進数として解釈される
  • 十進数として解釈される (0 始まりの八進数リテラルもある)
  • 十進数として解釈される (0o 始まりの八進数リテラルしかない)
  • 十進数として解釈される (そもそも八進数リテラルがない)

この他、 0 始まりの八進数リテラルがあるものの 0 が八進数扱いなのか十進数扱いなのか調べても分からなかったものもありました。

結果一覧

  • [2021-03-04 訂正: Go を 0o 始まりの八進数しかないグループに分類していましたが、 0 始まりの八進数もあるとの指摘を受けて訂正しました]
  • [2021-03-04 訂正: JIS 規格には記述があるとの情報を受けて Ruby を不明から十進数に分類し直しました]

    八進数

  • C

  • C++

十進数 (0 始まりの八進数もある)

  • Go (0 始まりと 0o 始まりの二種類の記法が可能)
  • Java
  • JavaScript (0 始まりと 0o 始まりの二種類の記法が可能)
  • Ruby (0 始まりと 0o 始まりの二種類の記法が可能)

十進数 (0o 始まりの八進数リテラルしかない)

  • Haskell
  • Python
  • Rust
  • Swift

十進数 (そもそも八進数リテラルがない)

  • C#
  • D
  • Kotlin
  • Scala

不明

各言語の 0 の解釈の詳細

0 始まりの八進数が書ける言語についての 0 の解釈の詳細です。

C

ISO/IEC 9899:2018 6.4.4.1 Integer constants の段落 1 より:

integer-constant:
        decimal-constant integer-suffixₒₚₜ
        octal-constant integer-suffixₒₚₜ
        hexadecimal-constant integer-suffixₒₚₜ

decimal-constant:
        nonzero-digit
        decimal-constant digit

octal-constant:
        0
        octal-constant octal-digit
...

十進定数 (decimal-constant) はゼロ以外 (nonzero-digit) から始まるものと定義されているので 0 が十進数と解釈される余地がありません。
何より八進定数 (octal-constant) に燦然と輝く 0。というわけで C では 0 は八進数。

C++

ISO/IEC 14882:2020 5.13.2 Integer literals [lex.icon] より:

integer-literal :
        binary-literal integer-suffixₒₚₜ
        octal-literal integer-suffixₒₚₜ
        decimal-literal integer-suffixₒₚₜ
        hexadecimal-literal integer-suffixₒₚₜ

binary-literal :
        0b binary-digit
        0B binary-digit
        binary-literal ₒₚₜ binary-digit

octal-literal :
        0
        octal-literal ₒₚₜ octal-digit

decimal-literal :
        nonzero-digit
        decimal-literal ₒₚₜ digit
...

C と比べると constant という言い回しが literal になっていたり二進数表記や桁区切りもできるようになっていたりとやや違いはありますが 0 に注目してみると C と同じ。
十進数は 0 から始まることができず八進数に明示的に 0 があります。

Go

The Go Programming Language Specification の Integer literals より:

A single 0 is considered a decimal zero.

と、 0 は十進数と明記されています。形式的定義では

int_lit        = decimal_lit | binary_lit | octal_lit | hex_lit .
decimal_lit    = "0" | ( "1" … "9" ) [ [ "_" ] decimal_digits ] .
binary_lit     = "0" ( "b" | "B" ) [ "_" ] binary_digits .
octal_lit      = "0" [ "o" | "O" ] [ "_" ] octal_digits .
hex_lit        = "0" ( "x" | "X" ) [ "_" ] hex_digits .

となっています。十進数リテラル (decimal_lit) に 0 が明示的に含まれ、八進数リテラル (octal_lit) には 0 の後に一桁以上必要です。

Java

The Java® Language Specification Java SE 15 Edition の 3.10.1. Integer Literals より:

DecimalNumeral:
 0
 NonZeroDigit [Digits]
 NonZeroDigit Underscores Digits
...

と、十進数 (DecimalNumeral) に明示的に 0 が入っているので 0 は十進数です。
なお八進数の定義は

OctalNumeral:
 0 OctalDigits
 0 Underscores OctalDigits
...

と、 0 の後に一桁以上必要な定義になっています。

JavaScript

ECMAScript® 2020 Language Specification の 11.8.3 Numeric Literals より:

DecimalIntegerLiteral::
  0
  NonZeroDigit DecimalDigitsₒₚₜ

なので Java と同様に 0 は十進数。
JavaScript の八進数は 0 始まりと 0o 始まりの二種類がありますが、 0 始まりの方の定義があるのは B.1.1 Numeric Literals。 strict mode では使えない記法。

LegacyOctalIntegerLiteral::
  0 OctalDigit
  LegacyOctalIntegerLiteral OctalDigit

ここも Java と同様、 0 の後に一桁以上必要な定義。

Ruby

Ruby-Doc.org では見付けられなかったため、現行の Ruby より古いですが ISO/IEC 30170:2012 8.7.6.2 Numeric Literals より。0 の扱いなんてそうそう変わりませんよね?

decimal-integer-literal ::
 unprefixed-decimal-integer-literal
| prefixed-decimal-integer-literal

unprefixed-decimal-integer-literal ::
 0
| decimal-digit-except-zero ( _? decimal-digit )∗

prefixed-decimal-integer-literal ::
 0 ( d | D ) digit-decimal-part
...
octal-integer-literal ::
 0 ( _ | o | O )? octal-digit ( _? octal-digit )∗

0d 始まりの十進数というのもあるんですね。
それはさておき、 Java 等と同様に十進数の定義 (プレフィックスなし十進整数リテラル -- unprefixed-decimal-integer-literal) に明示的に 0 が入っており、八進数は先頭の 0 の他に一桁以上必要な定義になっています。

(以下 Ruby を不明と分類していた時の内容)
Ruby Syntax の Numeric literals の例しか見付けることができませんでした。

123
  integer
-123
  integer(signed)
1_234
  integer(underscore within decimal numbers ignored)
123.45
  floating point number
1.2e-3
  floating point number
0xffff
  hexadecimal integer
0b01011
  binary integer
0377
  octal integer
?a
  ASCII code for character `a'(97)
...

この記述からは 0 がどちらなのか不明。これまた気にしていない気もします。

Perl

perlnumber の SYNOPSIS の記述程度しか見付けることができませんでした。

$n = 1234;              # decimal integer
$n = 0b1110011;         # binary integer
$n = 01234;             # octal integer
$n = 0x1234;            # hexadecimal integer
$n = 12.34e-56;         # exponential notation
$n = "-12.34e56";       # number specified as a string
$n = "1234";            # number specified as a string

これだけでは 0 が十進数なのか八進数なのか不明。そもそも 0 が十進数なのか八進数なのかという些細なことは気にしていないのかもしれません。

おわりに

今回調べた範囲で 0 が八進数として解釈されるのは C と C++ のみで、他はすべて十進数扱いでした。C と C++ は何故異端っぷりを発揮しているのか……

149
71
13

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
149
71