web-dev-qa-db-ja.com

値を別の表現に変換してから、それを元の場所に変換するコードは不適切ですが、どうやって?

私は 悪いプログラミング慣行に関する記事 を読んでいました。

それは言及しました-

値を別の表現に変換し、それを開始位置に変換する「ヨーヨーコード」(例:10進数を文字列に変換してから10進数に戻す、または文字列をパディングしてからトリミングする)

彼が与えた特定の例がプログラムを書くのに悪い方法である理由がわかりません。状況がそれを必要とする場合、値を使用できるように変換し直すことは私には問題ないようです。

誰もがこれについてもっと説明できますか?

35
user13107

doが数値の数値表現と文字列表現の両方を必要とする場合でも、どちらかが必要になるたびに再度変換するのではなく、一度だけ変換して元の値に留める方がよい。

原則として、いつものように存在しないコードに微妙な欠陥を含めることはできませんですが、存在するコードはしばしば存在します。それは偏執的に聞こえるかもしれませんが、経験からそれは適切であることがわかります。 「私はこの複雑なシステムを理解するのに十分なほど賢くない」という恒久的な軽い不安でプログラミングに取り組むなら、あなたは正しい道を進んでいます。

125
Kilian Foth

次の3つの主な理由で悪いです。

  1. これは、変数が実際にどのタイプ/形式であるかを考えていないことを示していますが、代わりにその時点で必要なものに変換しています。これはデザイン思考の欠如を示しています。
  2. それはおそらく無駄です。ほぼ確実にサイクルとコード行を無駄にし、そこにある必要のない変換を行っています。これにより、コードが必要以上に遅くなり、肥大化します。
  3. 型変換は微妙なエラーを起こしがちです。これらの変換をコード全体に点在させることで、エラーの可能性が高まります。

理由1は、それが言及されたコンテキストに基づいてソースが考えていた理由だと思います。

23
Jack Aidley

私は説明を「オリジナルを同じかそれ以上に行うことができる何かを行うために、型を別の表現に変換するコードと言い換えます次に変換します。何かを別のタイプに変換し、それに基づいて動作し、変換し直すことが完全に適切であり、失敗これを行うと、不正な動作が発生します。

変換が良い例:
1つは、大きさが最大1,000倍異なる可能性がある任意の符号の4つのfloat値を持ち、最後の場所で合計を0.625単位以内に計算する必要があります。 4つの値すべてをdoubleに変換し、合計を計算して、結果をfloatに戻すことは、floatのみを使用するアプローチよりもはるかに効率的です。
浮動小数点値は、最も正確な場合、最後の場所で0.5ユニット(ULP)です。この例では、最悪の場合の丸め誤差が、最適な最悪の場合の誤差を25%超えないようにする必要があります。 doubleを使用すると、0.5001 ULP内で正確な値が生成されます。 0.625 ULP要件は不自然に思えるかもしれませんが、そのような要件は逐次比較アルゴリズムでしばしば重要になります。エラー範囲がより厳密に指定されているほど、最悪の場合の反復要件は低くなります。

変換が悪い例:
1つは浮動小数点数を持ち、その値を一意に表す文字列を出力したいと考えています。 1つのアプローチは、数値を特定の桁数の文字列に変換し、それを元に戻して、結果が一致するかどうかを確認することです。

しかし、これは実際には貧弱なアプローチです。 10進文字列が2つの浮動小数点値の中間点にほぼ正確に位置する値を表す場合、string-to-floatメソッドが常により近いfloat値を生成することを保証するには、かなりのコストがかかります。そして、多くのそのような変換方法は、そのような保証を支持しません(とりわけ、そうすることは、それが数十億桁の長さであったとしても、場合によっては数のすべての桁を読むことを必要とするでしょう)。

メソッドが常に、表現された値の最後の場所(ULP)で0.5625単位以内の値を返すことを保証する方がはるかに安価です。堅牢な「リバーシブル」の10進数から文字列へのフォーマットルーチンは、出力値が正しい値からどれだけ離れているかを計算し、0.25(ULP)でない場合は結果が0.375(ULP)以内になるまで数字を出力し続けます。それ以外の場合、一部の変換メソッドが正しく処理する文字列を出力することがありますが、他の変換メソッドはできません。

誤って解釈される可能性のある値を出力するよりも、「必要でない」可能性のある数字を出力する方がよい場合があります。重要な点は、出力する桁数の決定は、特定のメソッドが文字列を数値に変換しようとした結果ではなく、出力プロセスに関連する数値計算に基づいて行う必要があるということです。

6
supercat

様々な理由

  1. それは無意味であり、複雑さを追加します-作成して維持するコードの量と必要なCPU時間の両方の点で

    1. 精度が低下したり、値が完全に破損したりする可能性があります

    2. 必要な数の表現をより多く保存することになるため、メモリを浪費します(言語によっては潜在的に)

受信するすべてのデータについて、可能な限り最初の最も正確な表現を維持することをお勧めします。このデータを使用してすべての計算を実行し、出力または読みやすい形式で表示する必要がある場合にのみ変換してください。

2
Jon Story

どうして?私たちの最高の人でも間違いをすることができるからです。

Microsoftが特に浮動小数点<->文字列変換が安全であることを確認するために「往復」形式を実装しようとしたときに何が起こったかを見てください: https://stackoverflow.com/q/24299692/541686

0
user541686

私が学校(および電気工学のポストスクール)にいたとき、私たちは乗算後に割り算をするように教えられました。除算は、多くの桁で丸められます。除算後に乗算すると、除算誤差が乗算されます。

型変換は同じで、データを失うリスクがあります。 CInt(1.3)= 1。

私の言語、Basicでは、型変換のみを実行します(VB6プログラムは、ランタイムが行うすべてのAPI呼び出しに対して、90%の時間をANSI/Unicode変換に費やしています)。

タイプ変換は、私たちが行うすべてのことを意味しています。

 Print 5

文字列「5」は、数値リテラルから出力されます。

form1.caption = "My Form"

Unicode文字列リテラルはANSI文字列に変換され、フォームパッケージによってSetWindowsTextAに送信されます。

これでも基本的に機能します

a = "5"
b = 3

c = a + b (= 8)

私は最近、バリアントプログラマーです-タイプについてさえ考えていません。私は自動変換に依存しています。

とにかく、私の3つのペットのおしっこは

それらを使用するために変数に文字列リテラルを割り当てる(メモリを浪費し、遅くなる)

コードがインラインである可能性がある場合の無意味な関数(そしてコンパイラはおそらく関数を元に戻し、とにかくインライン化します)

End Functionまたはプログラムの終了前の最後の行として、すべてのオブジェクトをなしに設定します。

ショートプログラムの4番目

5行のプログラムで3つの変数を無意味に暗くします。

0
triggeradeadcat