此 Stored Procedure 可將輸入的 IEEE 754 標準二進制浮點格式 (32 bits) 轉換為十進制數字輸出。
IEEE 754 共分為 S (Sign)、E (Exponent)、M (Mantisa) 三個部分 -
計算方式:以 11000010011100010000000000000000 為例
1) 將此數分為 S、E、M 三部分 (S = 1、E = 10000100、M = 11100010000000000000000)
2) S = 1 得知此數為負數 (若為正數則設定為 0)
3) 將 E 轉換為十進制再減去 127,得到 5 (此為 2 的乘方)。
4) 將 M 的左方加上 "1." (即 1.1110001) 後,將小數點右移 5 位,得到 111100.01。
5) 將 111100.01 轉為十進制,得到 60.25 。
6) 最後結果為 -60.25
程式碼
NOTE 欲複製程式碼的讀者,先將滑鼠指標移至程式碼區,雙擊 (Double-Click) 滑鼠左鍵,此時該區程式碼應會呈現 Highlight 狀態;再按下滑鼠右鍵,於出現的選單中選擇複製。若程式碼未出現 Highlight 狀態,請重整 (Refresh) 本網頁後,再重複上述動作。
if object_id ('usp_IEEE754_Restore') is not null drop proc usp_IEEE754_Restore go create proc usp_IEEE754_Restore @prm_IEEE_754_string varchar(32), @rtn_decimal_number float output /*----------------------------------------------------------------------------------+ | Author: Wei-jie Yang | | Date: 2012/05/10 | | All Rights Reserved | | | | [Description] | | This stored procedure is used to convert IEEE 754 binary floating number to | | decimal floating number. | | | | [Parameters] | | (1).INPUT Parameter | | - @prm_IEEE_754_string: The IEEE 754 number that you want to convert. | | (2).OUTPUT Parameter | | - @rtn_decimal_number : Converted decimal number | | | | [Usage] | | declare @return_1 float | | exec usp_IEEE754_Restore '11000010111100000100000000000000', @return_1 output | | select @return_1 as Decimal_Mode | +----------------------------------------------------------------------------------*/ as declare @abs_binary_exp int, @add_digit_number tinyint, @dot_left_digits int, @dot_position int, @dot_right_digits int, @binary_exp int, @binary_exp_string varchar(8), @binary_float_string varchar(50), @binary_float_string_dot_left_part varchar(50), @binary_float_string_dot_right_part varchar(50), @binary_float_string_length int, @decimal_fraction float, @decimal_integer int, @digit_counter int, @i tinyint, @j tinyint, @k tinyint, @shift_string varchar(50), @single_digit char(1) -- Binary Exponential ----------------------------------------------- select @binary_exp_string = substring(@prm_IEEE_754_string, 2, 8) select @binary_exp = 0 select @i = 8 while @i >= 1 begin select @single_digit = substring(@binary_exp_string, @i, 1) select @binary_exp = @binary_exp + power(2, 8 - @i) * cast(@single_digit as tinyint) select @i = @i - 1 end select @binary_exp = @binary_exp - 127 --------------------------------------------------------------------- -- Binary Float ----------------------------------------------------- select @binary_float_string = '1.' + substring(@prm_IEEE_754_string, 10, 23) -- Use '.' to split binary string into two parts select @dot_position = charindex('.', @binary_float_string) if @dot_position > 0 begin select @binary_float_string_length = len(@binary_float_string) select @binary_float_string_dot_left_part = substring(@binary_float_string, 1, @dot_position - 1) select @binary_float_string_dot_right_part = substring(@binary_float_string, @dot_position + 1, @binary_float_string_length - @dot_position) end else begin select @binary_float_string_dot_left_part = @binary_float_string select @binary_float_string_dot_right_part = '' end -- Process Binary Exponential if @binary_exp > 0 begin select @shift_string = substring(@binary_float_string, @dot_position + 1, @binary_exp) select @binary_float_string_dot_left_part = @binary_float_string_dot_left_part + @shift_string if len(@binary_float_string_dot_right_part) = @binary_exp begin select @binary_float_string_dot_right_part = '' end else begin if len(@binary_float_string_dot_right_part) < @binary_exp -- range exceeded begin if substring(@prm_IEEE_754_string, 1, 1) = '1' begin select @rtn_decimal_number = 1073741824 * -1 goto Error_Handler end else begin select @rtn_decimal_number = 1073741824 goto Error_Handler end end select @binary_float_string_dot_right_part = substring(@binary_float_string_dot_right_part, @binary_exp + 1, len(@binary_float_string_dot_right_part) - @binary_exp) end end else if @binary_exp < 0 begin select @binary_float_string_dot_left_part = '' select @add_digit_number = 1 select @abs_binary_exp = abs(@binary_exp) while @add_digit_number <= abs(@binary_exp) begin if @add_digit_number = 1 begin select @binary_float_string_dot_right_part = '1' + @binary_float_string_dot_right_part end else begin select @binary_float_string_dot_right_part = '0' + @binary_float_string_dot_right_part end select @add_digit_number = @add_digit_number + 1 end end --------------------------------------------------------------------- -- Generate Decimal Integer ----------------------------------------- select @dot_left_digits = len(@binary_float_string_dot_left_part) select @decimal_integer = 0 select @j = @dot_left_digits select @digit_counter = 1 while @j >= 1 begin select @single_digit = substring(@binary_float_string_dot_left_part, @digit_counter, 1) select @decimal_integer = @decimal_integer + power(2, @j - 1) * cast(@single_digit as tinyint) select @j = @j - 1 select @digit_counter = @digit_counter + 1 end -------------------------------------------------------------------- -- Generate Decimal Fraction ---------------------------------------- select @dot_right_digits = len(@binary_float_string_dot_right_part) select @decimal_fraction = 0 select @k = 1 while @k <= @dot_right_digits begin select @single_digit = substring(@binary_float_string_dot_right_part, @k, 1) if @single_digit <> 0 begin if @k <= 30 begin select @decimal_fraction = @decimal_fraction + (1 / (power (2, @k) * 1.0)) * cast(@single_digit as tinyint) end else -- exceed range begin select @decimal_fraction = @decimal_fraction + (1 / (power (2, 30) * 1.0)) * cast(@single_digit as tinyint) end end select @k = @k + 1 end --------------------------------------------------------------------- if substring(@prm_IEEE_754_string, 1, 1) = '1' select @rtn_decimal_number = (@decimal_integer + @decimal_fraction) * -1 else select @rtn_decimal_number = (@decimal_integer + @decimal_fraction) return