2个值应该相同但不是

时间:2011-04-13 01:39:34

标签: iphone objective-c hex uicolor

我有以下代码,它输入有人输入的HEX代码并将其转换为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。有任何想法吗?我认为这与第二位代码返回一个不准确的十六进制代码有关,但不确定如何在这种情况下使这更准确?

1 个答案:

答案 0 :(得分:2)

可能是浮点精度问题。使用floatdouble并不会像使用intlong那样存储确切的值。它存储IEEE-754 spec所允许的精确值的最接近的近似值。存储值和精确值之间的差异通常非常小,但它可能足够大,当您转换回整数时,您的值会被截断为下一个较小的整数。这就是您的输出中发生的情况(即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);
    }
}