diff --git a/conversion/hexadecimaltobinary.go b/conversion/hexadecimaltobinary.go new file mode 100644 index 000000000..a0d262df6 --- /dev/null +++ b/conversion/hexadecimaltobinary.go @@ -0,0 +1,78 @@ +/* +Author: mapcrafter2048 +GitHub: https://github.com/mapcrafter2048 +*/ + +// This algorithm will convert any Hexadecimal number(0-9, A-F, a-f) to Binary number(0 or 1). +// https://en.wikipedia.org/wiki/Hexadecimal +// https://en.wikipedia.org/wiki/Binary_number +// Function receives a Hexadecimal Number as string and returns the Binary number as string. +// Supported Hexadecimal number range is 0 to 7FFFFFFFFFFFFFFF. + +package conversion + +import ( + "errors" + "regexp" + "strings" +) + +var isValidHex = regexp.MustCompile("^[0-9A-Fa-f]+$").MatchString + +// hexToBinary() function that will take Hexadecimal number as string, +// and return its Binary equivalent as a string. +func hexToBinary(hex string) (string, error) { + // Trim any leading or trailing whitespace + hex = strings.TrimSpace(hex) + + // Check if the hexadecimal string is empty + if hex == "" { + return "", errors.New("input string is empty") + } + + // Check if the hexadecimal string is valid + if !isValidHex(hex) { + return "", errors.New("invalid hexadecimal string: " + hex) + } + + // Parse the hexadecimal string to an integer + var decimal int64 + for i := 0; i < len(hex); i++ { + char := hex[i] + var value int64 + if char >= '0' && char <= '9' { + value = int64(char - '0') + } else if char >= 'A' && char <= 'F' { + value = int64(char - 'A' + 10) + } else if char >= 'a' && char <= 'f' { + value = int64(char - 'a' + 10) + } else { + return "", errors.New("invalid character in hexadecimal string: " + string(char)) + } + decimal = decimal*16 + value + } + + // Convert the integer to a binary string without using predefined functions + var binaryBuilder strings.Builder + if decimal == 0 { + binaryBuilder.WriteString("0") + } else { + for decimal > 0 { + bit := decimal % 2 + if bit == 0 { + binaryBuilder.WriteString("0") + } else { + binaryBuilder.WriteString("1") + } + decimal = decimal / 2 + } + } + + // Reverse the binary string since the bits are added in reverse order + binaryRunes := []rune(binaryBuilder.String()) + for i, j := 0, len(binaryRunes)-1; i < j; i, j = i+1, j-1 { + binaryRunes[i], binaryRunes[j] = binaryRunes[j], binaryRunes[i] + } + + return string(binaryRunes), nil +} diff --git a/conversion/hexadecimaltobinary_test.go b/conversion/hexadecimaltobinary_test.go new file mode 100644 index 000000000..c2dee9712 --- /dev/null +++ b/conversion/hexadecimaltobinary_test.go @@ -0,0 +1,46 @@ +package conversion + +import ( + "testing" +) + +func TestHexToBinary(t *testing.T) { + tests := []struct { + hex string + want string + wantErr bool + }{ + {"", "", true}, + {"G123", "", true}, + {"12XZ", "", true}, + {"1", "1", false}, + {"A", "1010", false}, + {"10", "10000", false}, + {"1A", "11010", false}, + {"aB", "10101011", false}, + {"0Ff", "11111111", false}, + {" 1A ", "11010", false}, + {"0001A", "11010", false}, + {"7FFFFFFFFFFFFFFF", "111111111111111111111111111111111111111111111111111111111111111", false}, + } + + for _, tt := range tests { + t.Run(tt.hex, func(t *testing.T) { + got, err := hexToBinary(tt.hex) + if (err != nil) != tt.wantErr { + t.Errorf("hexToBinary(%q) error = %v, wantErr %v", tt.hex, err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("hexToBinary(%q) = %v, want %v", tt.hex, got, tt.want) + } + }) + } +} + +func BenchmarkHexToBinary(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _ = hexToBinary("7FFFFFFFFFFFFFFF") + } +} diff --git a/conversion/hexadecimaltodecimal.go b/conversion/hexadecimaltodecimal.go new file mode 100644 index 000000000..f0d7a81d3 --- /dev/null +++ b/conversion/hexadecimaltodecimal.go @@ -0,0 +1,57 @@ +/* +Author: mapcrafter2048 +GitHub: https://github.com/mapcrafter2048 +*/ + +// This algorithm will convert any Hexadecimal number(0-9, A-F, a-f) to Decimal number(0-9). +// https://en.wikipedia.org/wiki/Hexadecimal +// https://en.wikipedia.org/wiki/Decimal +// Function receives a Hexadecimal Number as string and returns the Decimal number as integer. +// Supported Hexadecimal number range is 0 to 7FFFFFFFFFFFFFFF. + +package conversion + +import ( + "fmt" + "regexp" + "strings" +) + +var isValidHexadecimal = regexp.MustCompile("^[0-9A-Fa-f]+$").MatchString + +// hexToDecimal converts a hexadecimal string to a decimal integer. +func hexToDecimal(hexStr string) (int64, error) { + + hexStr = strings.TrimSpace(hexStr) + + if len(hexStr) == 0 { + return 0, fmt.Errorf("input string is empty") + } + + // Check if the string has a valid hexadecimal prefix + if len(hexStr) > 2 && (hexStr[:2] == "0x" || hexStr[:2] == "0X") { + hexStr = hexStr[2:] + } + + // Validate the hexadecimal string + if !isValidHexadecimal(hexStr) { + return 0, fmt.Errorf("invalid hexadecimal string") + } + + var decimalValue int64 + for _, char := range hexStr { + var digit int64 + if char >= '0' && char <= '9' { + digit = int64(char - '0') + } else if char >= 'A' && char <= 'F' { + digit = int64(char - 'A' + 10) + } else if char >= 'a' && char <= 'f' { + digit = int64(char - 'a' + 10) + } else { + return 0, fmt.Errorf("invalid character in hexadecimal string: %c", char) + } + decimalValue = decimalValue*16 + digit + } + + return decimalValue, nil +} diff --git a/conversion/hexadecimaltodecimal_test.go b/conversion/hexadecimaltodecimal_test.go new file mode 100644 index 000000000..4f399fe46 --- /dev/null +++ b/conversion/hexadecimaltodecimal_test.go @@ -0,0 +1,52 @@ +package conversion + +import ( + "testing" +) + +func TestHexToDecimal(t *testing.T) { + tests := []struct { + hex string + want int64 + wantErr bool + }{ + {"", 0, true}, + {"G123", 0, true}, + {"123Z", 0, true}, + {"1", 1, false}, + {"A", 10, false}, + {"10", 16, false}, + {"1A", 26, false}, + {"aB", 171, false}, + {"0Ff", 255, false}, + {" 1A ", 26, false}, + {"0x1A", 26, false}, + {"0X1A", 26, false}, + {"1A", 26, false}, + {"7FFFFFFFFFFFFFFF", 9223372036854775807, false}, + {"0001A", 26, false}, + {"0000007F", 127, false}, + {"0", 0, false}, + {"0x0", 0, false}, + } + + for _, tt := range tests { + t.Run(tt.hex, func(t *testing.T) { + got, err := hexToDecimal(tt.hex) + if (err != nil) != tt.wantErr { + t.Errorf("hexToDecimal(%q) error = %v, wantErr %v", tt.hex, err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("hexToDecimal(%q) = %v, want %v", tt.hex, got, tt.want) + } + }) + } +} + +func BenchmarkHexToDecimal(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _ = hexToDecimal("7FFFFFFFFFFFFFFF") + } +}