2 个值应该相同但不是

发布于 2024-11-01 16:02:13 字数 2709 浏览 0 评论 0原文

我有以下代码,它接受某人输入的十六进制代码并将其转换为 HSB:

NSString *cString = [[hexText.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
    // String should be 6 or 8 characters
    if ([cString length] < 6) NSLog(@"UH OH");
    // strip 0X if it appears
    if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2];
    if ([cString length] != 6) NSLog(@"UH OH");
    // Separate into r, g, b substrings
    NSRange range;
    range.location = 0;
    range.length = 2;
    NSString *rString = [cString substringWithRange:range];
    range.location = 2;
    NSString *gString = [cString substringWithRange:range];
    range.location = 4;
    NSString *bString = [cString substringWithRange:range];
    // Scan values
    unsigned int r, g, b;
    [[NSScanner scannerWithString:rString] scanHexInt:&r];
    [[NSScanner scannerWithString:gString] scanHexInt:&g];
    [[NSScanner scannerWithString:bString] scanHexInt:&b];

    float red = r / 255.0f;
    float green = g / 255.0f;
    float blue = b / 255.0f;

    float colorArray[3];
    colorArray[0] = red; 
    colorArray[1] = green; 
    colorArray[2] = blue;
    int max;
    int min;

    min=0;
    max=0;
    for(int i=1; i<3; i++)
    {
        if(colorArray[i] > colorArray[max])
            max=i;
        if(colorArray[i] < colorArray[min])
            min=i;
    }

    if(max==min)
    {
        h3=0;
        s3=0;
        b3=colorArray[0];
    }
    else
    {
        b3=colorArray[max];

        s3=(colorArray[max]-colorArray[min])/(colorArray[max]);

        if(max==0) // Red
            h3 = (colorArray[1]-colorArray[2])/(colorArray[max]-colorArray[min])*60/360;
        else if(max==1) // Green
            h3 = (2.0 + (colorArray[2]-colorArray[0])/(colorArray[max]-colorArray[min]))*60/360;
        else // Blue
            h3 = (4.0 + (colorArray[0]-colorArray[1])/(colorArray[max]-colorArray[min]))*60/360;
    }

然后我有这段代码,它执行相反的操作 - 将 HSB 转换为十六进制代码:

    UIColor *forC = colourPreview.backgroundColor;

const CGFloat *c = CGColorGetComponents([forC CGColor]);

    CGFloat r, g, b;  
    r = c[0];  
    g = c[1];  
    b = c[2];  

    if (r < 0.0f) r = 0.0f;  
    if (g < 0.0f) g = 0.0f;  
    if (b < 0.0f) b = 0.0f;  

    if (r > 1.0f) r = 1.0f;  
    if (g > 1.0f) g = 1.0f;  
    if (b > 1.0f) b = 1.0f;  

    hexWithoutHash = [NSString stringWithFormat:@"%02X%02X%02X",  
                        (int)(r * 255), (int)(g * 255), (int)(b * 255)];  

这些应该都给出相同的值,并且大多数情况下都是如此。但有时我会输入十六进制代码,例如 208DBC,它会返回 1F8CBC。有什么想法吗?我认为这与第二位代码返回不准确的十六进制代码有关,但不确定在这种情况下如何使其更准确?

I have the following code which takes a HEX code somebody entered and transforms it into HSB:

NSString *cString = [[hexText.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
    // String should be 6 or 8 characters
    if ([cString length] < 6) NSLog(@"UH OH");
    // strip 0X if it appears
    if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2];
    if ([cString length] != 6) NSLog(@"UH OH");
    // Separate into r, g, b substrings
    NSRange range;
    range.location = 0;
    range.length = 2;
    NSString *rString = [cString substringWithRange:range];
    range.location = 2;
    NSString *gString = [cString substringWithRange:range];
    range.location = 4;
    NSString *bString = [cString substringWithRange:range];
    // Scan values
    unsigned int r, g, b;
    [[NSScanner scannerWithString:rString] scanHexInt:&r];
    [[NSScanner scannerWithString:gString] scanHexInt:&g];
    [[NSScanner scannerWithString:bString] scanHexInt:&b];

    float red = r / 255.0f;
    float green = g / 255.0f;
    float blue = b / 255.0f;

    float colorArray[3];
    colorArray[0] = red; 
    colorArray[1] = green; 
    colorArray[2] = blue;
    int max;
    int min;

    min=0;
    max=0;
    for(int i=1; i<3; i++)
    {
        if(colorArray[i] > colorArray[max])
            max=i;
        if(colorArray[i] < colorArray[min])
            min=i;
    }

    if(max==min)
    {
        h3=0;
        s3=0;
        b3=colorArray[0];
    }
    else
    {
        b3=colorArray[max];

        s3=(colorArray[max]-colorArray[min])/(colorArray[max]);

        if(max==0) // Red
            h3 = (colorArray[1]-colorArray[2])/(colorArray[max]-colorArray[min])*60/360;
        else if(max==1) // Green
            h3 = (2.0 + (colorArray[2]-colorArray[0])/(colorArray[max]-colorArray[min]))*60/360;
        else // Blue
            h3 = (4.0 + (colorArray[0]-colorArray[1])/(colorArray[max]-colorArray[min]))*60/360;
    }

I then have this code which does the opposite - transforms HSB into a hex code:

    UIColor *forC = colourPreview.backgroundColor;

const CGFloat *c = CGColorGetComponents([forC CGColor]);

    CGFloat r, g, b;  
    r = c[0];  
    g = c[1];  
    b = c[2];  

    if (r < 0.0f) r = 0.0f;  
    if (g < 0.0f) g = 0.0f;  
    if (b < 0.0f) b = 0.0f;  

    if (r > 1.0f) r = 1.0f;  
    if (g > 1.0f) g = 1.0f;  
    if (b > 1.0f) b = 1.0f;  

    hexWithoutHash = [NSString stringWithFormat:@"%02X%02X%02X",  
                        (int)(r * 255), (int)(g * 255), (int)(b * 255)];  

These should both give the same value, and most of the time it does. But sometimes I will type in a hex code such as 208DBC and it will return 1F8CBC. Any ideas? I think it's something to do with the second bit of code returning an inaccurate hex code, but not sure how to make this more accurate in this case?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

樱娆 2024-11-08 16:02:13

可能是浮点精度问题。使用 floatdouble 并不像使用 intlong 那样存储精确的值。它存储 IEEE-754 规范 允许的精确值的最接近近似值。存储值和精确值之间的差异通常非常小,但它可能足够大,以至于当您转换回整数时,您的值会被截断为下一个较小的整数。这就是输出中发生的情况(即 0x1F = 0x20 - 10x8C = 0x8D - 1)。

下面的代码可以说明这个问题:

for (int redColor = 0; redColor < 256; redColor++) {
    int originalRed = redColor;
    float red = originalRed / 255.0f;
    float redMultiplied = red * 255;
    int newRed = (int)redMultiplied;

    if (newRed != originalRed) {
        NSLog(@"Value mismatch detected:  origianlRed=%d, red=%f, redMultiplied=%f, newRed=%d", 
              originalRed, red, redMultiplied, newRed);
    }
}

Could be a floating-point precision issue. Using a float or a double does not store an exact value as using an int or long does. It stores the closest approximation of the exact value allowed by the IEEE-754 spec. The difference between the stored value and the exact value is generally very small, but it may be just big enough that when you convert back to an integer your value gets truncated to the next smaller integer. That is what is happening in your output (i.e. 0x1F = 0x20 - 1, 0x8C = 0x8D - 1).

The following code may illustrate the issue:

for (int redColor = 0; redColor < 256; redColor++) {
    int originalRed = redColor;
    float red = originalRed / 255.0f;
    float redMultiplied = red * 255;
    int newRed = (int)redMultiplied;

    if (newRed != originalRed) {
        NSLog(@"Value mismatch detected:  origianlRed=%d, red=%f, redMultiplied=%f, newRed=%d", 
              originalRed, red, redMultiplied, newRed);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文