iOS Swift/SwiftUI二进制计算器:浮点数与负数转二进制方案问询
解决Swift中浮点数(含负数)转二进制的问题
首先明确:整数二进制和浮点数二进制的表示逻辑完全不同,浮点数遵循IEEE 754标准,通过符号位、指数位、尾数位编码,不能直接套用整数的转换方法。以下是针对你的二进制计算器场景的具体实现方案:
一、实现浮点数与二进制的互转函数
针对Double类型(三角函数运算默认返回Double),可以通过内存操作获取其IEEE 754双精度二进制表示,同时支持反向转换:
// 将Double转换为IEEE 754双精度二进制字符串(64位) func doubleToBinaryString(_ value: Double) -> String { var value = value let data = Data(bytes: &value, count: MemoryLayout<Double>.size) let bits = data.flatMap { byte in (0..<8).reversed().map { bit in (byte >> bit) & 1 == 1 ? "1" : "0" } } return bits.joined() } // 将IEEE 754双精度二进制字符串转回Double func binaryStringToDouble(_ binaryString: String) -> Double? { guard binaryString.count == 64 else { return nil } let bytes = stride(from: 0, to: 64, by: 8).map { startIndex in let byteRange = binaryString.index(binaryString.startIndex, offsetBy: startIndex)..<binaryString.index(binaryString.startIndex, offsetBy: startIndex+8) return UInt8(String(binaryString[byteRange]), radix: 2)! } var value: Double = 0 withUnsafeMutableBytes(of: &value) { buffer in bytes.enumerated().forEach { offset, byte in buffer[offset] = byte } } return value }
如果需要单精度Float的转换,只需把Double替换为Float,MemoryLayout<Double>.size改为MemoryLayout<Float>.size,二进制长度限制为32位即可。
二、适配三角函数运算的代码逻辑
修改你现有代码中处理三角函数的分支,完成「二进制输入→十进制浮点数→计算→二进制输出」的流程:
let expression = "sin(101)*sin(101)" // 输入为二进制字符串101(对应十进制5) let separator = "*" let components = expression.components(separatedBy: separator) var newString = "" for component in components { // 处理三角函数分支 if component.contains("sin") || component.contains("cos") || component.contains("tan") || component.contains("sinh") || component.contains("cosh") || component.contains("tanh") { // 用正则提取函数名和括号内的二进制输入 let regex = try! NSRegularExpression(pattern: "(sin|cos|tan|sinh|cosh|tanh)\\((.*?)\\)") if let match = regex.firstMatch(in: component, range: NSRange(component.startIndex..., in: component)) { let funcName = String(component[Range(match.range(at: 1), in: component)!]) let binaryInput = String(component[Range(match.range(at: 2), in: component)!]) // 二进制转十进制整数,再转为Double用于计算 guard let decimalInt = binaryStringToInt(binaryInput) else { continue } let decimalDouble = Double(decimalInt) // 执行三角函数计算 var result: Double = 0 switch funcName { case "sin": result = sin(decimalDouble) // 默认接收弧度参数,如需角度请用sin(decimalDouble * .pi / 180) case "cos": result = cos(decimalDouble) case "tan": result = tan(decimalDouble) case "sinh": result = sinh(decimalDouble) case "cosh": result = cosh(decimalDouble) case "tanh": result = tanh(decimalDouble) default: continue } // 将计算结果拼接到表达式中 newString += "\(result) \(separator)" } } else { // 原有整数运算逻辑保持不变 newString += "\(binaryStringToInt(component) ?? 0) \(separator)" } } newString.removeLast(separator.count) if let finalValue = parser.parse(newString)?.value { // 将最终结果转为二进制展示 let resultBinary = doubleToBinaryString(finalValue) print("十进制结果:\(finalValue)") print("二进制结果(IEEE 754双精度):\(resultBinary)") }
三、关键细节说明
- 弧度/角度切换:Swift标准库的三角函数默认接收弧度参数,如果你的计算器需要按角度计算,需先将十进制值转为弧度:
sin(decimalDouble * .pi / 180) - 二进制展示优化:64位二进制串较长,可拆分展示符号位、指数位、尾数位,提升可读性:
let fullBinary = doubleToBinaryString(finalValue) let signBit = fullBinary.prefix(1) let exponentBits = fullBinary.dropFirst().prefix(11) let mantissaBits = fullBinary.dropFirst(12) print("符号位:\(signBit),指数位:\(exponentBits),尾数位:\(mantissaBits)") - 精度保障:上述转换是严格遵循IEEE 754标准的编码转换,不会丢失浮点数本身的精度(除非超出类型的数值范围)。
内容的提问来源于stack exchange,提问作者Muhammad Danish Qureshi
相关产品推荐
相关产品推荐

