LoginSignup
0
1

More than 3 years have passed since last update.

Uint8ClampedArrayに小数を代入すると詰まる

Last updated at Posted at 2019-12-01

先に結論だけ

Uint8ClampedArrayに小数を代入すると、0.5以下が切り捨てられます。複合代入演算子を利用しても同様です。

この記事の想定する環境

この記事は以下の環境で動作することを想定しています。

  • Google Chrome 78.0.3904.108

記事を読む前に、お手元の環境をご確認ください。

Uint8ClampedArrayとは

Uint8ClampedArrayは、8ビット符号なし整数値の配列です。JavaScriptのNumberは、浮動小数点を扱いますがこの配列は0 ~ 255の整数値に値が制限されます。Uint8ClampedArrayなどのTypedArrayは型付きの要素の配列です。

どのような操作で必要となるのか

Canvas要素のImageDataオブジェクトが、ピクセルデータをUint8ClampedArrayで格納しています。TypedArrayは一般的に、バイナリデータをJavaScriptで操作する際のインターフェイスです。

小数を代入してみる

このUint8ClampedArrayに、小数を代入するとどのような振る舞いをするでしょう?情報がなかったため、Codepenでテストコードを書いてみました。

const array = new Uint8ClampedArray(1);

for( let i = 1; i < 101; i++){
  const val =  1.0 - (i / 100)
  array[0] = val;
  console.log( val , array[0] )
}

このコードの出力は以下の通りです。

0.99 1
pen.js:7 0.98 1
pen.js:7 0.97 1
...(中略)...
pen.js:7 0.51 1
pen.js:7 0.5 0
pen.js:7 0.49 0
...(中略)...
pen.js:7 0.020000000000000018 0
pen.js:7 0.010000000000000009 0
pen.js:7 0 0

0.5以下が切り捨て、それ以上では1に丸め込みが行われていました。四捨五入ではなく0.5で切り捨てが行われているのは意外でした。

どんなときに困るのか

JavaScriptのNumber型は浮動小数点なので、うっかり以下のようなコードを書いてしまうとバグを生みます。

array[0] *= 0.8;

このコードではarray[0]が2以下になると、数値がそれ以上減りません。丸め込み処理が行われるためです。例としてCanvasのピクセルを徐々に暗くしたいのに、いつまでもわずかな灰色が残ります。

array[0] = ( array[0] * 0.8 ) | 0;

Math.floorやビット演算で明示的に小数を切り捨てると、この問題は解決します。

参考記事 : HTML5 canvas のパフォーマンスの改善 / 浮動小数点座標の使用を控える

整数型を持った言語では当然問題になるコードですが、JavaScriptでも同様の注意が必要となる場合があります。
とくにCanvasを操作する場合はご注意ください。

以上、ありがとうございました。

0
1
0

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
0
1