整数定数にアンダースコアを許可しない言語では、10億の定数を作成することをお勧めしますか?


39

整数リテラルアンダースコアを許可しない言語では、10億の定数を作成することをお勧めしますか?たとえば、C ++の場合:

size_t ONE_BILLION = 1000000000;

確かに、100のような小さな数値に対して定数を作成するべきではありません。しかし、9個のゼロがあると、次のようなコードにゼロを残したり、余分なものを追加したりするのは間違いなく簡単です:

tv_sec = timeInNanosec / 1000000000;
tv_nsec = timeInNanosec % 1000000000;

24
ここのみんながNOに投票することを望みます。そうすれば、プログラマーが定数を使用せずにゼロを置き忘れたために、いつか私の銀行が10億ドルを口座に振り込むかもしれません!:)
Reactgular

43
小さい数の定数を作成してみませんか?100はどういう意味ですか?何らかの文脈がない限り、それは魔法の数字です。
アラン

4
@MathewFoscarini一般的に、間違いはどちらの方法でも起こり得ます。しかし、あなたの銀行に関して言えば、間違いは常にあなたに反するでしょう。
エモリー

23
考えてみましょう書き込み1e910^9または1_000_000_000言語場合はサポートし、それを使用しています。
ハンマー

回答:


33

ほとんどの言語は、ある種の指数表記を備えています。100万は1e6、(10の6乗の1倍を意味する)です。これは基本的に、ここでのほとんどの命題よりもさらに問題を解決します。

しかし、Cライクな言語の多くでは、科学表記法浮動小数点型を定義していますが、これは本当にintが必要な場合は残念です。ただし、その定数を簡単に型キャストして、フォーミュラでの暗黙的な変換を回避できます。

n / int(1e9) 10億で割ります。

物理量(ナノ秒単位の時間)を扱う例では、一般に整数が正しいタイプかどうかを自問します。実際、double測定可能な量を扱う場合、浮動小数点の方が適している可能性があります(もちろん、aを好む場合もありますlong long)。


6
私はNANOSECONDS_IN_ONE_SECONDソリューションがはるかに明確できれいだと思う
トーマスボニーニ

1
質問は整数自由主義に関するものであり、科学表記法の使用を提案します。これを適切に行うか、定数を定義するかは、質問で求められなかった構造化コードの問題です。定数を定義すると抽象化が制限されるため、より優れた抽象化を実現するために変換関数/マクロを
作成します-wirrbel

1
非常に大きなdoubleをintにキャストすると、浮動小数点数の典型的な丸め差異の問題が発生しませんか?
フィリップ

通常の精度の整数型では、倍精度浮動小数点数を使用して変換する限り、これは問題になりません。long long範囲の値を使用する場合は正しいです。
ウィルベル

145

代わりに、NANOSECONDS_IN_ONE_SECONDと呼ばれるものを作成します。

または、考えられるならより短い、より良い名前。


58
私は言うだろうNanoseconds_Per_Secondが、これは、私の意見では、正しい答えです。
KChaloux

8
@Mathew私はあなたのポイントを得ることができません。メートルあたりのミリメートルと言っても何も問題はありません。あなたはそれが冗長であることを暗示しているかもしれません、そのナノ秒は10億分の1秒を意味しますが、それを再び述べることに何の問題もありません。それは時にXより多くの意味を作るために続け、yが互いに素で、「半ダースあたりの単位」または「ミリ秒ナノ秒」のように「Xあたりのyの」1 + 1 = 2を言うようなものだ
マーク・カンラス

7
@MathewFoscarini実際、いや、この文脈ではそうではありません。もしそうなら、名前NANOSECONDSが付けられた定数は、何に適用するかわからないので無意味です。同様に、NANOSECONDS_PER_MICROSECOND意味のある同様の有効な定数です。
イズカタ

5
@MathewFoscarini、「メートルあたりのミリメートル」は、変換時に単位を削除して未加工の値を取得する方法です。1mm/1m = 1000、これはまさにここで行われていることのポイントです。
zzzzBov

11
なぜそんなにタイピングするのですか?NS_PER_SECナノ秒に対処する必要がある人には明らかなはずです。
レックスカー

67

定数は、数字に意味を与えるためのものです。ONE_BILLIONtoには追加の意味はありません1000000000。実際、異なる自然言語では、10億は異なるもの(10億または100万)を意味するため、混乱を招きます!もっと短く書きたい場合は、プログラミング言語で科学表記法の使用が許可されている可能性があります1e9。それ以外の場合、@ JohnBに同意します。この数値は実際には1秒あたりのナノ秒数を意味するので、名前を付けてください。


9
さまざまな言語で10億個のゼロが異なることを意味することを指摘しておくと良いでしょう。
フローズンコイ

3
通常の言語を自然言語に変更することをお勧めします。通常は何か他のものを意味します...
jk。

言語の「十億」の異なる解釈はこのような良い点です!なぜ私はあなたの答えを二度アップできないのです!
DSF

3
別の言語は必要ありません。別の国は必要ありません。英国英語では、「億」とは公式の通信(マスメディアと政府)で1974年の前後で異なるものを意味し、両方の使用法がまだ存在します。
ヨルグWミットタグ

1
10000000000.にONE_BILLIONに追加の意味ありません、私は反対する(ヒント:私は意図的にあなたを誤って引用し、別のゼロを追加し、私はそれを言及していなかった場合には気づいていたでしょう?)。。
キース・トンプソン

27

1つまたは2つの使用法では、次の規則を使用します。

tv_sec = timeInNanosec / (1000 * 1000 * 1000);
tv_nsec = timeInNanosec % (1000 * 1000 * 1000);

それは完全に自明であり、定数にコンパイルされ、手間がかかりません。

また、次のような場合にも非常に便利です。

var Time = 24 * 60 * 60;

数日のうちに1日について話しているのが見やすい場所です。


これは私が通常行うことです。また、昨日NANOSECONDS_IN_ONE_SECONDを定義し、今日NANOSECONDS_PER_SECONDを定義したことを忘れないという利点もあります。そしておそらく明日はONE_AMERICAN_BILLION。
トーマスパドロン-マッカーシー

確かに 'SecondsInOneDay = 24 * 60 * 60'はまだ簡単ですか?
-JBRウィルキンソン

@JBRWilkinson確かに、私の最初のスニペットはクラスを使用していましたinstance.Time = ...が、その後、私はそれを馬鹿にした
...-Sklivvz

3
CまたはC ++では、(1000 * 1000 * 1000)intは16ビットである必要があるため、オーバーフローする可能性があります。(1000L * 1000L * 1000L)それを避けるために書くことができます。
キーストンプソン

私はこれをたくさんします。とてもうまくいきます。
vy32

10

値の長さは、定数が必要かどうかを定義するものではありません。

入力を避けるためではなく、定数を使用してマジックナンバーを避けます。

たとえば、これらは完全に有効な定数です。

public static final int CLOSE_CURSORS_AT_COMMIT = 1;
public static final int CONCUR_READ_ONLY = 2;
public static final int CONCUR_UPDATABLE = 3;
public static final int FETCH_FORWARD = 4;
public static final int FETCH_REVERSE = 5; 
public static final int FETCH_UNKNOWN = 6;
public static final int HOLD_CURSORS_OVER_COMMIT = 7;
public static final int TYPE_FORWARD_ONLY = 8;
public static final int TYPE_SCROLL_INSENSITIVE = 9;
public static final int TYPE_SCROLL_SENSITIVE = 10;

つかいます:

public static final int NANOSECS_PER_SECOND = 1000000000;

(コードサンプルはJavaで、お気に入りの言語に翻訳します)


3
+1名前付きの数字はほとんど役に立たない。定数の目的は、それらの数字に意味を与えることです。それらは何を表していますか?それらは、係数を数えたり、制限したり、正式に命名したりしますか?カウントの値ではありません。
JustinC


2
これらは有効な定数の恐ろしい例です。列挙型の前に作成された場合を除き、列挙型である必要がありました。
クリストファーハン

@ChristofferHammarströmこれらは実際に列挙の前に作成されたもので、Java SDKのSQLパッケージのResultSetクラスの一部です。
Tulainsコルドバ

2
@ChristofferHammarström列挙型がありますが、意味のないことではないので、彼らは悪いです。これらのクラスが作成されたとき、Enumは存在しませんでした。FETCH_FORWARDやFETCH_REVERSEなどの相互に排他的なオプションを区別するために、異なる値が与えられています。値は重要ではなく、それらが異なるという事実だけです。
Tulainsコルドバ

8

アメリカまたはヨーロッパの10億?

(または、技術的には、10億の短スケールまたは長スケール-1つは1億、もう1つは100万です)。

この混乱を考えると、私はイエスと言います-それを一度定義してそれを維持するのは理にかなっています、同様にあなたが定義に同意する必要がある定数に適用されます-一度定義してください。


17
「アメリカやヨーロッパの10億?」-「なに?わからない!ああ!!!!」
Tesserex

少なくとも英国では、それ以来、長い間、110億ドルを採用しています。
ジャックエイドリー

1
@Tesserex-まあ、あなたは王であるときにこれらのことを知っている必要があります、あなたは知っています。
gbjbaanb

5

しない理由

まず、下線を記述したり、トリックを使用してシミュレートしたりしない理由があります。コード内で定数を見つけるのが難しくなります。あるプログラムが、その操作のどこかで、いくつかのパラメーターにハードコーディングされた値1500000を示しているとします。プログラムのソースコードのどこでこれが実際に発生するかを知りたいので、コードをgrepして、1500000何も見つかりません。どうして?16進数である可能性があります(ただし、そのような丸い10進数の場合)。私には知られていないが、定数は実際にはと書かれてい1_500_000ます。正規表現が必要でした1_?500_?000

コメントのガイドキャラクター

1種類の視覚教材が利用できない、または上記の理由でそれを使用したくないからといって、代替視覚教材を作成するためにテキストファイルの2つの次元を利用できないという意味ではありません。

foo = bar / 1000000000;
//           --^--^--^  

これにより、3つのゼロからなる3つのグループがあることを簡単に確信できます。それでも、ソースコードをgrepして1000000000、見つけることができます。

構文の色付け

プログラム可能な構文の色付けを備えたテキストエディタは、読みやすさを向上させるために、色を交互に変えて数値定数の数字をグループ化できます。コードで何もする必要はありません。

前処理:C、C ++、Objective C

ここで、数字と数字の間にコンマが必要な場合は、CとC ++でいくつかの前処理を使用できます。

/* Four digit base TH-ousand constant macro */
/* Condensed using Horner's rule */
#define TH(A,B,C,D) ((((((A) * 1000) + (B)) * 1000) + (C)) * 1000 + D)

tv_sec = nanoseconds / TH(1,000,000,000)

のような数字で動作しますTH(1,234,567,890)

THに似たマクロは、算術ではなくトークンの貼り付けでも機能します。Cプリプロセッサでは、2 ##つのオペランドを1つのトークンに貼り付けるために、マクロ演算子で2項演算子(「トークンペースト」)を使用できます。オペランドの一方または両方をマクロ引数にすることができます。ここでのマイナス面(私たちにとってリスクを生み出します)は、結果の連結が有効なトークンでない場合、動作が未定義になることです。

#define TOK4(A, B, C, D) A ## B ## C ## D

いま

TOK4(1,000,000,000)       /* produces the single token 1000000000 */
TOK4(1,123,000,000.0E+2)  /* produces the single token 1123000000.0E+2 */
TOK4(pr,in,t,f)           /* produces the token printf */
TOK4(#,*,a,b)             /* undefined behavior, #*ab is not valid token syntax */

識別子を貼り付けて結果を使用してグローバル変数と関数に名前を付けるCプログラムが存在し、GNU id-utilsやctagsなどのツールの影響を受けないため、使用するのが非常に困難です。


2
私が見たプリプロセッサの最高の悪用の1つに対して+1。ただし、私はまだNSEC_PER_SECまたは実稼働環境で使用します。
ビクター

プリプロセッサの乱用で非常に-1 :)
CVn

3

ええ、それは合理的なアイデアのようです。オフバイワンのDIGITエラーは、悪名高いオフバイワンのエラーよりもさらに悪化します。ただし、他の人(将来の自分を含む)がコードを読むのに混乱を招く可能性があります。

NANOSEC_PER_SECのようなより説明的な名前は、時間に使用される場所を明確にするため、良いようです。ただし、時間以外のコンテキストで使用することは意味がなく、すべての状況に対して個別の1,000,000,000を作成することは実用的ではありません。

あなたが本当にやりたいことは、最初は愚かに思えますが、「秒を超える」ことです。これにより、言語非依存(アメリカおよびヨーロッパでは10 ^ 9)であるだけでなく、状況非依存(単位に制限なし)であるNANO_PERが残り、入力および読み取りが容易になります。


この投稿は読みにくい(テキストの壁)。ですが、あなたは気編集をより良い形にそれをINGの?
gnat

3

一般に、単位変換にスカラー定数を使用することはお勧めできません。そのようなものに対して定数を作成していることに気付いた場合は、あまりにも多くの場所で変換を行っています。

ある単位の量(たとえば、10秒)があり、別の単位(つまり、ナノ秒)に変換する場合。これはまさに、あなたの言語の型システムを使用して、ユニットが意図したとおりに実際にスケーリングされることを保証するときです。

あなたの関数が取る作るNanosecondsパラメータを、そしてためにそのクラスで変換演算子および/またはコンストラクタを提供しSecondsMinutesまたは、何を持っている-あなたは。あなたのところですconst int#defineあるいは1e9他の回答で見られるが属します。

これにより、あいまいな単位の変数がコードの周りに浮かんでいるのを防ぎます。そして、間違った乗算/除算が適用された、または既に適用された、または量が実際に時間ではなく距離であった場所からのバグの全体の広がりを防ぎます...

また、このようなクラスでは、プレーンなスカラープライベートから構築し、静的な「MakeSeconds(int)」などを使用して、不透明な数値のずさんな使用を阻止するのが良いでしょう。

より具体的には、C ++でBoost.Chronoを確認してください


1
+少なくとも、タイムゾーンがよく悪用されているように、基本からのスケーリング係数またはオフセット係数を持つ共通タイプを使用します。
JustinC

1

私は個人的に、定数にする必要がある場合を除き、定数を作成することをお勧めしません。複数の場所に配置し、変更またはテストのためにファイルの先頭で定義することが絶対に役立つ場合。

タイプするのが面倒だから?いいえ。

個人的に、定数が定義されている他の誰かのコードを入手した場合、私はこれをコードの重要な側面だと一般的に考えています。たとえば、tcpキープアライブタイマー、許可される接続の最大数。デバッグしなければならなかった場合、おそらくそれがどこで使用されているのかを理解しようとして、不必要な注意を払うでしょう。


冗談は言うまでもありませんが、銀行のプログラマーがすべての番号に定数を付けなければならない場合、ソフトウェアを転送するのは巨大で、管理できず、遅くなります。私はそれがどのようなものか想像することができました。お金を送金するのに3営業日かかると言われたと想像してみてください。
サイモンマクラフリン

私の銀行は送金に3日かかります:(
Reactgular

1
@MathewFoscariniの銀行家は、プログラマーを必要としないExcelを使用しています;)
Mateusz

@Simon言語とコンパイラーに応じて、定数をコードに最適化する必要があり、オーバーヘッドはほとんどありません。私はあなたのポイントを理解していますが、マジックナンバーの代わりに名前を使用するとコードを読みやすくするためにどこでも定数を使用できます。
スティーブン

読みにくいのは、入力するのが難しいのではなく、はるかに問題です。
アルブ

0

質問のタイトルに「1000000000」ではなく「10億」と書いた理由を考えると、答えが「はい」である理由がわかります。


0

大きなリテラルの定数を作成しないでください。このようなリテラルごとに定数が必要になりますが、これは(私の意見では)完全な冗談です。構文の強調表示などの助けを借りずに、リテラルを必死に明確にする必要がある場合、関数またはマクロを作成して(より簡単に)生活を「簡単」にすることができます。

#define SPLIT3(x, y, z) x##y##z

int largeNumber1 = SPLIT3(123,456,789);
int largeNumber2 = 123456789;

0

私はこれをします:

const int Million = 1000 * 1000;
const int Billion = 1000 * Million;

または

const int SciMega = 1000 * 1000; const int SciGiga = 1000 * SciMega;

1秒あたりのナノ秒数について:nanoはギガの「逆」です。

Kilo  Mega  Giga   etc.
10^3  10^6  10^9
Milli Micro Nano   etc.
10^-3 10^-6 10^-9

「Sci」に注意してください-科学の場合、コンピューターのように、キロ、メガ、ギガなどの意味は異なります:1024(2 ^ 10)、1024 * 1024(2 ^ 20)など。2メガバイトは2,000,000バイトではありません。

UPDATE Commenterは、2のデジタル指数には特別な用語が存在することを指摘しました:http : //en.wikipedia.org/wiki/Mebibyte


「2メガバイトは2,000,000バイトではありません。」必要な回転プラッターハードディスクメーカーにお問い合わせください。(ダウン投票者ではない、ところで)
CVn

@michaelkjorlingこれはプログラミングの質問であり、ビジネス倫理やマーケティングの質問ではありません。ハードドライブについては同意しますが、それは別のトピックです。そして、反対票については痛い!
TA氏

1
実際、2メガバイトは2,000,000バイトです。2メビバイトは2,097,152バイトです。参照en.wikipedia.org/wiki/Mebibyte
vy32

@ vy32ありがとう、これまで聞いたことがない。それを反映するために私の答えを更新します。
TA氏

@ Mr.TA、問題ありません!コンピューターサイエンスをSIユニットに準拠させるために努力しています!クラブに加わる。
vy32
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.