/**
* Copyright umhr ( http://wonderfl.net/user/umhr )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/10Ye
*/
package
{
import com.bit101.components.InputText;
import com.bit101.components.Label;
import com.bit101.components.Style;
import com.bit101.components.TextArea;
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.ByteArray;
/**
* 単精度浮動小数点数
* http://ja.wikipedia.org/wiki/%E5%8D%98%E7%B2%BE%E5%BA%A6%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%95%B0
* ...
* @author umhr
*/
public class WonderflMain extends Sprite
{
private var _textArea:TextArea;
public function WonderflMain()
{
init();
}
private function init():void
{
if (stage) onInit();
else addEventListener(Event.ADDED_TO_STAGE, onInit);
}
private function onInit(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, onInit);
// entry point
Style.embedFonts = false;
Style.fontName = "_sans";
Style.fontSize = 12;
new Label(this, 8, 8, "Number:");
new InputText(this, 65, 8, "0.1", onCalc).width = 200;
_textArea = new TextArea(this, 8, 35);
_textArea.width = 450;
_textArea.height = 420;
start(0.1);
}
private function onCalc(e:Event):void {
var inputText:InputText = e.target as InputText;
var num:Number = Number(inputText.text);
_textArea.text = "";
start(num);
}
private function start(num:Number):void {
var byteArray:ByteArray = new ByteArray();
var binary:String;
_textArea.text += "入力値をNumber型に:" + num + "\n";
_textArea.text += "===============================\n";
_textArea.text += "倍精度(64bit)\n";
_textArea.text += "===============================\n";
_textArea.text += "ByteArrayを使用(模範解答)。\n";
_textArea.text += "writeDouble()で書き込んだものを二進数表示\n";
byteArray.writeDouble(num);
byteArray.position = 0;
binary = FloatingPoint.binaryFromByteArray(byteArray);
separater(binary);
byteArray.position = 0;
_textArea.text += "readDouble()でNumberに戻す:" + byteArray.readDouble() + "\n";
_textArea.text += "===============================\n";
_textArea.text += "独自計算。\n";
binary = FloatingPoint.binaryFromDecimal(num, true);
separater(binary);
_textArea.text += "二進数を倍精度でNumberに戻す:" + FloatingPoint.decimalFromBinary(binary) + "\n";
byteArray.length = 0;
_textArea.text += "===============================\n";
_textArea.text += "単精度(32bit)\n";
_textArea.text += "===============================\n";
_textArea.text += "ByteArrayを使用(模範解答)。\n";
_textArea.text += "writeFloat()で書き込んだものを二進数表示\n";
byteArray.writeFloat(num);
byteArray.position = 0;
binary = FloatingPoint.binaryFromByteArray(byteArray);
separater(binary);
byteArray.position = 0;
_textArea.text += "readFloat()でNumberに戻す:" + byteArray.readFloat() + "\n";
_textArea.text += "===============================\n";
_textArea.text += "独自計算。\n";
binary = FloatingPoint.binaryFromDecimal(num, false);
separater(binary);
_textArea.text += "二進数を単精度でNumberに戻す:" + FloatingPoint.decimalFromBinary(binary) + "\n";
}
private function separater(binary:String):void {
var isDouble:Boolean = binary.length == 64;
var sign:String = binary.substr(0, 1);
var exponent:String = isDouble?binary.substr(1, 11):binary.substr(1, 8);
var fraction:String = isDouble?binary.substr(12):binary.substr(9);
_textArea.text += "二進数 : " + binary + "\n";
_textArea.text += "符号部 : " + sign + "\n";
_textArea.text += "指数部 : " + exponent + "\n";
_textArea.text += "仮数部 : " + fraction + "\n";
}
}
}
import flash.utils.ByteArray;
/**
* ...
* @author umhr
*/
class FloatingPoint
{
public function FloatingPoint()
{
}
/**
* ByteArrayに書き込まれている二進数をStringとして返します。
* @param byteArray
* @return
*/
static public function binaryFromByteArray(byteArray:ByteArray):String {
var binary:String = "";
var n:int = byteArray.length;
for (var i:int = 0; i < n; i++)
{
binary += ("00000000" + byteArray.readUnsignedByte().toString(2)).substr( -8);
}
return binary;
}
/**
* 二進数をNumber(10進数)にして返します。
* 【参考】単精度浮動小数点数
* http://ja.wikipedia.org/wiki/%E5%8D%98%E7%B2%BE%E5%BA%A6%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%95%B0
* @param binary
* @return
*/
static public function decimalFromBinary(binary:String):Number {
var isDouble:Boolean = binary.length == 64;
var sign:String = binary.substr(0, 1);
var exponent:String = isDouble?binary.substr(1, 11):binary.substr(1, 8);
var fraction:String = isDouble?binary.substr(12):binary.substr(9);
var s:Number = calcSign(sign);
var result:Number;
if (parseInt(exponent) == 0) {
// 指数部が0の場合
if (parseInt(fraction) == 0) {
// 仮数部が0の場合
result = 0;
}else {
// 仮数部が0で無い場合
// 非正規化数
result = s * Math.pow(2, 2 - Math.pow(2, exponent.length) * 0.5) * calcFraction(fraction, 0);
}
}else if (parseInt(exponent, 2) == Math.pow(2, exponent.length) - 1) {
// 指数部が全て1の場合
if (parseInt(fraction) == 0) {
// 仮数部が0の場合
result = s * Infinity;
}else {
// 仮数部が0で無い場合
result = NaN;
}
}else {
// 正規化数
result = s * calcExponent(exponent) * calcFraction(fraction);
}
return result;
}
/**
* 符号部
* @param sign
* @return
*/
static private function calcSign(sign:String):Number
{
return Math.pow( -1, parseInt(sign));
}
/**
* 指数部
* @param exponent
* @return
*/
static private function calcExponent(exponent:String):Number
{
var result:Number = 1 - Math.pow(2, exponent.length) * 0.5;// -1023;
var pow:Number = 1;
var n:int = exponent.length;
for (var i:int = 0; i < n; i++)
{
result += (exponent.charAt(n - i - 1) == "1")?pow:0;
pow *= 2;
}
return Math.pow(2, result);
}
/**
* 仮数部
* @param fraction
* @param offset
* @return
*/
static private function calcFraction(fraction:String, offset:Number = 1):Number
{
var result:Number = offset;
var pow:Number = 0.5;
var n:int = fraction.length;
for (var i:int = 0; i < n; i++)
{
result += (fraction.charAt(i) == "1")?pow:0;
pow *= 0.5;
}
return result;
}
/**
* 十進数を二進数にして返します。
* @param decimal
* @param is64Bit
* @return
*/
static public function binaryFromDecimal(decimal:Number, is64Bit:Boolean = false):String {
var sign:String = (decimal < 0)?"1":"0";
decimal = Math.abs(decimal);
var exponentLength:int = is64Bit?11:8;
var fractionLength:int = (is64Bit?64:32) - exponentLength - 1;
//trace(sign, exponentLength, fractionLength);
var intNum:int = int(decimal);
var decNum:Number = decimal - intNum;
var intBi:String = binaryFromInt(intNum);
var dicBi:String = "";
var pos:int = 0;
var count:int = 0;
while (decNum != 0 && pos < fractionLength*2 && count <= fractionLength+intBi.length+1)
{
decNum *= 2;
dicBi += int(decNum).toString();
decNum = decNum - int(decNum);
if(parseInt(dicBi) > 0){
count ++;
}
pos ++;
}
//trace(dicBi,dicBi.length);
var shiftKeta:int;
if(intBi == "0"){
shiftKeta = -(dicBi.length - parseInt(dicBi, 2).toString(2).length + 1);
dicBi = dicBi.substr( -shiftKeta);
}else {
shiftKeta = intBi.length - 1;
dicBi = intBi.substr(1) + dicBi;
}
intBi = intBi.substr(0, 1);
var b:int = Math.pow(2, exponentLength) * 0.5 - 1;
var exponent:String = (get0String(exponentLength) + binaryFromInt(b + shiftKeta)).substr( -exponentLength);
return rounding(sign, exponent, dicBi, fractionLength);
}
/**
* 端数処理
* http://ja.wikipedia.org/wiki/%E7%AB%AF%E6%95%B0%E5%87%A6%E7%90%86
* @param dicBi
* @param fractionLength
* @return
*/
static private function rounding(sign:String, exponent:String, dicBi:String, fractionLength:int):String {
var body:String = dicBi.substr(0, fractionLength);
var tail:String = dicBi.substr(fractionLength);
trace(body, tail);
var fraction:String = (dicBi + get0String(fractionLength)).substr(0, fractionLength);
var result:String = sign + exponent + fraction;
if (tail.substr(0,2) == "10" || tail.substr(0,2) == "11") {
trace("繰り上がる!");
var zeroPoint:int = result.lastIndexOf("0");
result = result.substring(0, zeroPoint) + "1" + get0String(result.substring(zeroPoint + 1).length);
}else {
// tailが無い、00、01、1の場合
trace("繰り上がり無し");
}
sign = result.substr(0, sign.length);
exponent = result.substr(sign.length, exponent.length);
fraction = result.substr(sign.length + exponent.length, fraction.length);
return sign + exponent + fraction;
}
/**
* 指定の長さの0の文字列を返します。
* @param num
* @return
*/
static private function get0String(num:int):String {
var result:String = "";
for (var i:int = 0; i < num; i++)
{
result += "0";
}
return result;
}
/**
* intを二進数にして返します。
* @param num
* @return
*/
static private function binaryFromInt(num:int):String {
if (num == 0) {
return "0";
}
var result:String = "";
while (num > 0)
{
result = String(num % 2) + result;
num = num * 0.5;
}
return result;
}
}