2 значения должны быть одинаковыми, но не - PullRequest
1 голос
/ 13 апреля 2011

У меня есть следующий код, который берет введенный 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 Ответ

2 голосов
/ 13 апреля 2011

Может быть проблема точности с плавающей точкой.Использование float или double не сохраняет точное значение, как использование int или long.Он хранит самое близкое приближение точного значения, разрешенного спецификацией IEEE-754 .Разница между сохраненным значением и точным значением, как правило, очень мала, но может быть достаточно большой, чтобы при преобразовании обратно в целое число ваше значение усекалось до следующего меньшего целого числа.Это то, что происходит в вашем выводе (т.е. 0x1F = 0x20 - 1, 0x8C = 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);
    }
}
...