3

我在 NSString 中有一个非常大的十进制数,它太大而无法放入包括 NSDecimal 在内的任何变量中。我是手动做数学的,但如果我不能把这个数字放入一个变量中,那么我就不能把它除掉。那么转换字符串的好方法是什么?

示例输入:423723487924398723478243789243879243978234

输出:4DD361F5A772159224CE9EB0C215D2915FA

我在这里查看第一个答案,但它在 C# 中,我不知道它是客观的 C 等价物。

有没有人有任何不涉及使用外部库的想法?

4

1 回答 1

1

如果这就是您所需要的,那么实现起来并不难,特别是如果您愿意使用 Objective-C++。通过使用Objective-C++,你可以使用avector来管理内存,从而简化了代码。

这是我们将要实现的接口:

// NSString+BigDecimalToHex.h
@interface NSString (BigDecimalToHex)
- (NSString *)hexStringFromDecimalString;
@end

为了实现它,我们将一个任意精度的非负整数表示为 base-65536 位的向量:

// NSString+BigDecimalToHex.mm
#import "NSString+BigDecimalToHex.h"
#import <vector>

// index 0 is the least significant digit
typedef std::vector<uint16_t> BigInt;

“困难”部分是将 a 乘以BigInt10 并添加一个十进制数字。我们可以很容易地通过预加载进位的长乘法来实现这一点:

static void insertDecimalDigit(BigInt &b, uint16_t decimalDigit) {
    uint32_t carry = decimalDigit;
    for (size_t i = 0; i < b.size(); ++i) {
        uint32_t product = b[i] * (uint32_t)10 + carry;
        b[i] = (uint16_t)product;
        carry = product >> 16;
    }
    if (carry > 0) {
        b.push_back(carry);
    }
}

有了这个辅助方法,我们就可以实现接口了。首先,我们需要BigInt为每个十进制数字调用一次帮助方法,将十进制数字字符串转换为 a:

- (NSString *)hexStringFromDecimalString {
    NSUInteger length = self.length;
    unichar decimalCharacters[length];
    [self getCharacters:decimalCharacters range:NSMakeRange(0, length)];
    BigInt b;
    for (NSUInteger i = 0; i < length; ++i) {
        insertDecimalDigit(b, decimalCharacters[i] - '0');
    }

如果输入字符串为空或全为零,b则为空。我们需要检查一下:

    if (b.size() == 0) {
        return @"0";
    }

现在我们需要转换b为十六进制数字字符串。的最高有效数字b位于最高索引处。为避免前导零,我们将特别处理该数字:

    NSMutableString *hexString = [NSMutableString stringWithFormat:@"%X", b.back()];

然后我们将每个剩余的 base-65536 数字转换为四个十六进制数字,按照从最高有效到最低有效的顺序:

    for (ssize_t i = b.size() - 2; i >= 0; --i) {
        [hexString appendFormat:@"%04X", b[i]];
    }

然后我们就完成了:

    return hexString;
}

你可以在这个 gist中找到我的完整测试程序(作为 Mac 命令行程序运行)。

于 2013-03-13T21:31:13.217 回答