bitXor関数

本ページには広告が含まれています。

2つの数値のビット毎の排他的論理和を求めます。2つの数値の同じ位置にあるビットの片方が1のときは1、それ以外のときは0とした10進数の値を返します。指定できる数値は正の整数または小数で、負の値の場合はエラー値を返します。

構文
bitXor( arg1, arg2 )
引数
arg1 必須
数値1(10進数)
arg2 必須
数値2(10進数)
戻り値
2つの数値のビット毎の排他的論理和

プログラム

UWSC
//////////////////////////////////////////////////
// 【引数】
//   arg1 : 数値1(10進数) 
//   arg2 : 数値2(10進数) 
// 【戻り値】
//   2つの数値のビット毎の排他的論理和 
//////////////////////////////////////////////////
FUNCTION bitXor(arg1, arg2)
	DIM args[1] = arg1, arg2
	DIM bins[1]
	DIM decimals[1]
	DIM integers[1]
	DIM keta[1]
	IFB ABS(arg1) <> arg1 OR ABS(arg2) <> arg2 THEN
		RESULT = ERR_VALUE
		EXIT
	ENDIF
	FOR i = 0 TO 1
		bins[i] = decToBin(args[i])
		decimals[i] = 0
		IFB POS(".", bins[i]) <> 0 THEN
			integers[i] = COPY(bins[i], 1, POS(".", bins[i]) - 1)
			decimals[i] = COPY(bins[i], POS(".", bins[i]) + 1)
		ELSE
			integers[i] = bins[i]
		ENDIF
	NEXT
	keta[0] = IIF(LENGTH(integers[0]) > LENGTH(integers[1]), LENGTH(integers[0]), LENGTH(integers[1]))
	integers[0] = strPad(integers[0], keta[0], "0", LEFT)
	integers[1] = strPad(integers[1], keta[0], "0", LEFT)
	keta[1] = IIF(LENGTH(decimals[0]) > LENGTH(decimals[1]), LENGTH(decimals[0]), LENGTH(decimals[1]))
	decimals[0] = strPad(decimals[0], keta[1], "0", RIGHT)
	decimals[1] = strPad(decimals[1], keta[1], "0", RIGHT)
	DIM bin = ""
	FOR i = 1 TO keta[0]
		bin = bin + (VAL(COPY(integers[0], i, 1)) XOR VAL(COPY(integers[1], i, 1)))
	NEXT
	bin = bin + "."
	FOR i = 1 TO keta[1]
		bin = bin + (VAL(COPY(decimals[0], i, 1)) XOR VAL(COPY(decimals[1], i, 1)))
	NEXT
	RESULT = binToDec(bin)
FEND

//////////////////////////////////////////////////
// 【引数】
//   bin : 2進数 
//   signFlg : 符号付きならばTrue 
// 【戻り値】
//   10進数に変換した値 
//////////////////////////////////////////////////
FUNCTION binToDec(bin, signFlg = TRUE)
	DIM dec = 0
	DIM decimalFlg = IIF(POS(".", bin), TRUE, FALSE)
	IFB COPY(bin, 1, 1) = "1" AND signFlg THEN
		DIM msb = IIF(decimalFlg, POS(".", bin) - 1, LENGTH(bin))
		DIM lsb = IIF(decimalFlg, POS(".", bin) - LENGTH(bin), 0)
		DIM dec2 = POWER(2, msb) - 1
		FOR i = -1 TO lsb STEP -1
			dec2 = dec2 + POWER(2, i)
		NEXT
		DIM a = binToDec(bin, FALSE)
		DIM b = dec2
		dec = -1 * (bitXor(a, b) + POWER(2, lsb))
	ELSE
		IFB decimalFlg THEN
			DIM integer = COPY(bin, 1, POS(".", bin) - 1)
			DIM decimal = COPY(bin, POS(".", bin) + 1)
			FOR i = 1 TO LENGTH(decimal)
				dec = dec + COPY(decimal, i, 1) * POWER(2, -1 * i)
			NEXT
		ELSE
			integer = bin
		ENDIF
		FOR i = 1 TO LENGTH(integer)
			dec = dec + COPY(integer, i, 1) * POWER(2, LENGTH(integer) - i)
		NEXT
	ENDIF
	RESULT = dec
FEND

//////////////////////////////////////////////////
// 【引数】
//   num : 10進数もしくは2進数の値 
//   bit : ビット 
// 【戻り値】
//   ビットを反転した値 
//////////////////////////////////////////////////
FUNCTION bitNot(num, bit = EMPTY)
	IFB isString(num) THEN
		DIM res = ""
		FOR i = 1 TO LENGTH(num)
			DIM str = COPY(num, i, 1)
			IFB str = "0" OR str = "1" THEN
				res = res + (1 - VAL(str))
			ELSE
				res = res + str
			ENDIF
		NEXT
		RESULT = res
	ELSE
		DIM exponent = IIF(bit = EMPTY, CEIL(LOGN(2, num + 1)), bit)
		RESULT = POWER(2, exponent) - num - 1
	ENDIF
FEND

//////////////////////////////////////////////////
// 【引数】
//   dec : 10進数 
//   signFlg : 符号付きならばTrueを指定 
//   digits : 変換した2進数の桁数合わせを自動で行うかを示すブール値、もしくは桁数を表す数値(8,16,24,32,64のいずれか)を指定 
// 【戻り値】
//   2進数に変換した値 
//////////////////////////////////////////////////
FUNCTION decToBin(dec, signFlg = FALSE, digits = FALSE)
	// 負数で符号なしならばエラー値を返す
	IFB dec < 0 AND signFlg = FALSE THEN
		PRINT "負数の場合signFlgにTrueを指定してください"
		RESULT = ERR_VALUE
		EXIT
	ENDIF
	
	// digitsのビット数が足りなければエラー値を返す、負数なら1桁多く取る
	IFB VARTYPE(digits) <> VAR_BOOLEAN AND digits < CEIL(LOGN(2, ABS(dec))) + IIF(dec < 0, 1, 0) THEN
		PRINT "ビット数が足りません"
		RESULT = ERR_VALUE
		EXIT
	ENDIF
	
	// signFlgがTrueかつdigitsがFalseならばエラー値を返す
	IFB signFlg AND !digits THEN
		PRINT "signFlgがTrueのときdigitsはFalse以外を選択してください"
		RESULT = ERR_VALUE
		EXIT
	ENDIF

	// bin:2進数に変換した結果を代入する変数
	DIM bin = ""
	DIM decimalFlg = IIF(POS(".", dec) <> 0, TRUE, FALSE)
	DIM negativeFlg = IIF(dec < 0, TRUE, FALSE)
	dec = ABS(dec)
	
	// (1) 10進数を整数部と小数部に分ける
	DIM integer = IIF(decimalFlg, COPY(dec, 1, POS(".", dec) - 1), dec)
	DIM decimal = IIF(decimalFlg, "0." + COPY(dec, POS(".", dec) + 1), 0)

	// (2) 10進数(整数部)を2進数に変換する。
	REPEAT
		bin = (integer MOD 2) + bin
		integer = INT(integer / 2)
	UNTIL integer = 0

	// (3) 10進数(小数部)を2進数に変換する。
	IFB decimalFlg THEN
		bin = bin + "."
		DIM loop = 0
		REPEAT
			loop = loop + 1
			decimal = decimal * 2
			bin = bin + IIF(decimal >= 1, "1", "0")
			IF decimal > 1 THEN decimal = decimal - 1
		UNTIL decimal = 1 OR loop > 64
	ENDIF

	// digitsがFALSE以外なら
	IFB digits THEN
		// (4) 2進数の桁合わせを行う
		DIM tmp = bin
		DIM binInteger = TOKEN(".", tmp)
		DIM binDecimal = TOKEN(".", tmp)
		// 整数部、小数部を4bit単位になるまで拡張
		// 整数部、4の倍数になるまで整数部の先頭に'0'を追加
		IF LENGTH(binInteger) MOD 4 <> 0 THEN binInteger = strRepeat("0", 4 - LENGTH(binInteger) MOD 4) + binInteger
		// 小数部、4の倍数になるまで小数部の末尾に'0'を追加
		IF LENGTH(binDecimal) MOD 4 <> 0 THEN binDecimal = binDecimal + strRepeat("0", 4 - LENGTH(binDecimal) MOD 4)
		DIM digit = LENGTH(binInteger + binDecimal)

		// 10進数の場合、一旦自動調整を行う
		integer = INT(dec)

		IF signFlg AND COPY(binInteger, 1, 1) = "1" THEN binInteger = strRepeat("0", 4) + binInteger

		IFB signFlg THEN
			IFB integer >= -128 AND integer <= 127 THEN						// -2^7〜2^7-1
				binInteger = strRepeat("0", 8 - LENGTH(binInteger)) + binInteger
			ELSEIF integer >= -32768 AND integer <= 32767 THEN				// -2^15〜2^15-1
				binInteger = strRepeat("0", 16 - LENGTH(binInteger)) + binInteger
			ELSEIF integer >= -8388608 AND integer <= 8388607 THEN			// -2^23〜2^23-1
				binInteger = strRepeat("0", 24 - LENGTH(binInteger)) + binInteger
			ELSEIF integer >= -2147783648 AND integer <= 2147483647 THEN	// -2^31〜2^31-1
				binInteger = strRepeat("0", 32 - LENGTH(binInteger)) + binInteger
			ELSE
				binInteger = strRepeat("0", 64 - LENGTH(binInteger)) + binInteger
			ENDIF
		ELSE
			IFB integer <= 255 THEN				// 2^8-1
				binInteger = strRepeat("0", 8 - LENGTH(binInteger)) + binInteger		
			ELSEIF integer <= 65535 THEN		// 2^16-1
				binInteger = strRepeat("0", 16 - LENGTH(binInteger)) + binInteger		
			ELSEIF integer <= 16777215 THEN		// 2^24-1
				binInteger = strRepeat("0", 24 - LENGTH(binInteger)) + binInteger
			ELSEIF integer <= 4294967295 THEN	// 2^32-1
				binInteger = strRepeat("0", 32 - LENGTH(binInteger)) + binInteger
			ELSE
				binInteger = strRepeat("0", 64 - LENGTH(binInteger)) + binInteger
			ENDIF
		ENDIF

		totalDigits = LENGTH(binInteger + binDecimal)

		IFB totalDigits > 64 THEN
			DIM del32 = totalDigits - 32
			DIM del64 = totalDigits - 64
			IFB del32 = LENGTH(binDecimal) AND digits <> 64 THEN
				binDecimal = ""
				PRINT "32bitを超えたため、小数点以下を削除しました"
			ELSEIF del32 < LENGTH(binDecimal) AND digits <> 64 THEN
				binDecimal = COPY(binDecimal, 1, LENGTH(binDecimal) - del32)
				PRINT "32bitを超えたため、小数点以下の一部を削除しました"
			ELSEIF del64 = LENGTH(binDecimal) AND del64 <> 0 THEN
				binDecimal = ""
				PRINT "64bitを超えたため、小数点以下を削除しました"
			ELSEIF del64 < LENGTH(binDecimal) THEN
				binDecimal = COPY(binDecimal, 1, LENGTH(binDecimal) - del64)
				PRINT "64bitを超えたため、小数点以下の一部を削除しました"
			ELSE
				RESULT = ERR_VALUE
				PRINT "64bitを超えるため、変換できません"
				EXIT
			ENDIF
		ENDIF

		// 整数部、小数部の合計桁数を8,16,24,32,64bit単位になるまで拡張
		digit = LENGTH(binInteger + binDecimal)
		DIM array[] = 8, 16, 24, 32, 64
		FOR item IN array
			IFB digit <= item THEN
				binInteger = strRepeat("0", item - digit) + binInteger
				BREAK
			ENDIF
		NEXT

		// 指定ビットに調整
		// 合計桁数の再設定
		totalDigits = LENGTH(binInteger + binDecimal)
		
		IFB digits = TRUE THEN
			// 桁合わせを自動調整
			IFB totalDigits > 64 THEN
				len = LENGTH(binInteger + binDecimal)
				WHILE LENGTH(binInteger) > 8 AND len > digits
					IFB COPY(binInteger, 1, 4) = "0000" THEN
						binInteger = COPY(binInteger, 5)
						len = len - 4
					ELSE
						BREAK
					ENDIF
				WEND
	
				WHILE LENGTH(binDecimal) > 4 AND LENGTH(binInteger + binDecimal) > digits
				IFB COPY(binDecimal, LENGTH(binDecimal) - 4) = "0000" THEN
					binDecimal = COPY(binDecimal, 1, LENGTH(binDecimal) - 4)
					ELSE
						BREAK
					ENDIF
				WEND
				tmp = binInteger + "." + binDecimal

				binInteger = COPY(tmp, 1, POS(".", tmp) - 1)
				binDecimal = COPY(tmp, POS(".", tmp) + 1)
				totalDigits = LENGTH(binInteger + binDecimal)
				IFB totalDigits > 64 THEN
					RESULT = ERR_VALUE
					PRINT "64bitを超えたため変換できません"
					EXIT
				ENDIF
			ENDIF
		ELSE
			// 指定ビットに調整
			IFB totalDigits <= digits THEN
				binInteger = strPad(binInteger, digits - LENGTH(binDecimal), "0", LEFT)
			ELSE
				// 桁あふれ調整
				totalDigits = LENGTH(binInteger + binDecimal)

				len = LENGTH(binInteger + binDecimal)
				WHILE LENGTH(binInteger) > 8 AND len > digits
					IFB COPY(binInteger, 1, 4) = "0000" THEN
						binInteger = COPY(binInteger, 5)
						len = len - 4
					ELSE
						BREAK
					ENDIF
				WEND
	
				WHILE LENGTH(binDecimal) > 4 AND LENGTH(binInteger + binDecimal) > digits
				IFB COPY(binDecimal, LENGTH(binDecimal) - 4) = "0000" THEN
					binDecimal = COPY(binDecimal, 1, LENGTH(binDecimal) - 4)
					ELSE
						BREAK
					ENDIF
				WEND
				tmp = binInteger + "." + binDecimal

				binInteger = COPY(tmp, 1, POS(".", tmp) - 1)
				binDecimal = COPY(tmp, POS(".", tmp) + 1)
				len = LENGTH(binInteger + binDecimal)
				IFB len > digits THEN
					DIM deleteLength = len - digits
					IFB deleteLength = LENGTH(binDecimal) THEN
						binDecimal = ""
						PRINT "指定ビット数にするため小数点以下を削除しました"
					ELSEIF deleteLength < LENGTH(binDecimal) THEN
						binDecimal = COPY(binDecimal, 1, LENGTH(binDecimal) - deleteLength)
						PRINT "指定ビット数にするため小数点以下の一部を削除しました"
					ELSE
						RESULT = ERR_VALUE
						PRINT "指定ビット数では変換できません"
						EXIT
					ENDIF
				ENDIF
			ENDIF
		ENDIF

		bin = binInteger + IIF(binDecimal <> "", "." + binDecimal, "")

		// (5) 入力値がマイナスのため、2進数をマイナス値に変換する
		IFB negativeFlg THEN
			// 1の補数
			bin = bitNot(bin)
			// 2の補数
			DIM res = ""
			DIM carry = "1"
			FOR i = LENGTH(bin) TO 1 STEP -1
				IFB carry = "1" THEN
					SELECT COPY(bin, i, 1)
						CASE "0"
							res = "1" + res
							carry = 0
						CASE "1"
							res = "0" + res
						DEFAULT
							res = COPY(bin, i, 1) + res
					SELEND
				ELSE
					res = COPY(bin, i, 1) + res
				ENDIF
			NEXT
			bin = res
		ENDIF
	ENDIF
	RESULT = bin
FEND

//////////////////////////////////////////////////
// 【引数】
//   expr : 評価する式 
//   truepart : 評価した式がTrueのときに返す値 
//   falsepart : 評価した式がFalseのときに返す値 
// 【戻り値】
//   truepart : 評価した式がTrueのとき、falsepart : 評価した式がFalseのとき 
//////////////////////////////////////////////////
FUNCTION IIF(expr, truepart, falsepart)
	IFB EVAL(expr) THEN
		RESULT = truepart
	ELSE
		RESULT = falsepart
	ENDIF
FEND

//////////////////////////////////////////////////
// 【引数】
//   variable : 型を調べる変数 
// 【戻り値】
//    : TRUE : 与えられた変数が文字列型である、 
//   FALSE : 与えられた変数が文字列型でない、 : 
//////////////////////////////////////////////////
FUNCTION isString(variable)
	RESULT = IIF(VARTYPE(variable) = VAR_ASTR OR VARTYPE(variable) = VAR_USTR, TRUE, FALSE)
FEND

//////////////////////////////////////////////////
// 【引数】
//   num : 符号を求める数値 
// 【戻り値】
//   1 : 正の数、0 : ゼロ、-1 : 負の数、ERR_VALUE : それ以外 
//////////////////////////////////////////////////
FUNCTION sign(num)
	SELECT TRUE
		CASE !CHKNUM(num)
			RESULT = ERR_VALUE
		CASE num > 0
			RESULT = 1
		CASE num = 0
			RESULT = 0
		CASE num < 0
			RESULT = -1
	SELEND
FEND

//////////////////////////////////////////////////
// 【引数】
//   input : 入力文字列 
//   length : 埋めたあとの長さ 
//   str : 埋める文字 
//   type : 埋める方向 
// 【戻り値】
//   指定文字で埋めた文字列 
//////////////////////////////////////////////////
FUNCTION strPad(input, length, str = " ", type = RIGHT)
	DIM s = ""
	SELECT type
		CASE LEFT
			FOR i = 1 TO CEIL((length - LENGTH(input)) / LENGTH(str))
				s = s + str
			NEXT
			input = COPY(s, 1, length - LENGTH(input)) + input
		CASE RIGHT
			FOR i = 1 TO CEIL((length - LENGTH(input)) / LENGTH(str))
				s = s + str
			NEXT
			input = input + COPY(s, 1, length - LENGTH(input))
	SELEND
	RESULT = input
FEND

//////////////////////////////////////////////////
// 【引数】
//   inputs : 繰り返す文字列 
//   multiplier : inputsを繰り返す回数 
// 【戻り値】
//   inputsをmultiplier回を繰り返した文字列を返します 
//////////////////////////////////////////////////
FUNCTION strRepeat(inputs, multiplier)
	DIM res = ""
	FOR n = 1 TO multiplier
		res = res + inputs
	NEXT
	RESULT = res
FEND

使い方

UWSC
PRINT bitXor(5789.375, 7754.75)
結果
プレーンテキスト
2263.625

関連記事

bitAnd関数 (自作関数)
2つの数値のビット毎の論理積を求めます。
bitOr関数 (自作関数)
2つの数値のビット毎の論理和を求めます。