32/64位设备上的Objective-C划分产生不同的结果

时间:2015-04-08 15:42:54

标签: ios objective-c c math arm

如标题中所述,当我尝试执行以下divsion时,根据设备的体系结构,我会得到两种不同的结果:

unsigned int a = 42033;
unsigned int b = 360;
unsigned int c = 466
double result = a / (double)(b * c);
// on arm64 -> result = 0.25055436337625181
// on armv7 -> result = 0.24986030696800732

为什么结果不匹配?

根据Apple 64-Bit Transition Guide for Cocoa Touch,这些数据类型在32位和64位运行时具有相同的大小。

修改

完整的代码:

#import "UIImage+MyCategory.h"

#define CLIP_THRESHOLD 0.74 // if this much of the image is the clip color, leave it alone

typedef struct {
    unsigned int leftNonColorIndex;
    unsigned int rightNonColorIndex;
    unsigned int nonColorCount;
} scanLineResult;

static inline scanLineResult scanOneLine(unsigned int *scanline, unsigned int count, unsigned int color, unsigned int mask) {
    scanLineResult result = {UINT32_MAX, 0, 0};

    for (int i = 0; i < count; i++) {
        if ((*scanline++ & mask) != color) {
            result.nonColorCount++;
            result.leftNonColorIndex = MIN(result.leftNonColorIndex, i);
            result.rightNonColorIndex = MAX(result.rightNonColorIndex, i);
        }
    }

    return result;
}

typedef struct {
    unsigned int leftNonColorIndex;
    unsigned int topNonColorIndex;
    unsigned int rightNonColorIndex;
    unsigned int bottomNonColorIndex;
    unsigned int nonColorCount;

    double colorRatio;
} colorBoundaries;

static colorBoundaries findTrimColorBoundaries(unsigned int *buffer,
                                               unsigned int width,
                                               unsigned int height,
                                               unsigned int bytesPerRow,
                                               unsigned int color,
                                               unsigned int mask)
{
    colorBoundaries result = {UINT32_MAX, UINT32_MAX, 0, 0, 0.0};
    unsigned int *currentLine = buffer;

    for (int i = 0; i < height; i++) {
        scanLineResult lineResult = scanOneLine(currentLine, width, color, mask);
        if (lineResult.nonColorCount) {
            result.nonColorCount += lineResult.nonColorCount;
            result.topNonColorIndex = MIN(result.topNonColorIndex, i);
            result.bottomNonColorIndex = MAX(result.bottomNonColorIndex, i);
            result.leftNonColorIndex = MIN(result.leftNonColorIndex, lineResult.leftNonColorIndex);
            result.rightNonColorIndex = MAX(result.rightNonColorIndex, lineResult.rightNonColorIndex);
        }

        currentLine = (unsigned int *)((char *)currentLine + bytesPerRow);
    }

    double delta = result.nonColorCount / (double)(width * height);
    result.colorRatio = 1.0 - delta;

    return result;
}

@implementation UIImage (MyCategory)

- (UIImage *)crop:(CGRect)rect {

    rect = CGRectMake(rect.origin.x * self.scale,
                      rect.origin.y * self.scale,
                      rect.size.width * self.scale,
                      rect.size.height * self.scale);

    CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], rect);
    UIImage *result = [UIImage imageWithCGImage:imageRef
                                          scale:self.scale
                                    orientation:self.imageOrientation];
    CGImageRelease(imageRef);
    return result;
}

- (UIImage*)trimWhiteBorders {
#ifdef __BIG_ENDIAN__
    // undefined
#else
    const unsigned int whiteXRGB = 0x00ffffff;
    // Which bits to actually check
    const unsigned int maskXRGB = 0x00ffffff;
#endif

    CGImageRef image = [self CGImage];
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(image);

    // Only support default image formats
    if (bitmapInfo != (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host))
        return nil;

    CGDataProviderRef dataProvider = CGImageGetDataProvider(image);
    CFDataRef imageData = CGDataProviderCopyData(dataProvider);

    colorBoundaries result = findTrimColorBoundaries((unsigned int *)CFDataGetBytePtr(imageData),
                                                     (unsigned int)CGImageGetWidth(image),
                                                     (unsigned int)CGImageGetHeight(image),
                                                     (unsigned int)CGImageGetBytesPerRow(image),
                                                     whiteXRGB,
                                                     maskXRGB);

    CFRelease(imageData);

    if (result.nonColorCount == 0 || result.colorRatio > CLIP_THRESHOLD)
        return self;

    CGRect trimRect = CGRectMake(result.leftNonColorIndex,
                                 result.topNonColorIndex,
                                 result.rightNonColorIndex - result.leftNonColorIndex + 1,
                                 result.bottomNonColorIndex - result.topNonColorIndex + 1);


    return [self crop:trimRect];
}

@end

2 个答案:

答案 0 :(得分:0)

在iPad 3(armv7)和iPhone 6(arm64)上使用iOS 8.3 LLVM 6.1在Xcode 6.3.1中测试了下面的代码,它们产生的相同值至少达到15个精度。

unsigned int a = 42033;
unsigned int b = 360;
unsigned int c = 466;
double result = a / (double)(b * c);
// on arm64 -> result = 0.25055436337625181
// on armv7 -> result = 0.24986030696800732

NSString *msg = [NSString stringWithFormat:@"result: %.15f", result];

[[[UIAlertView alloc] initWithTitle:@"" message:msg delegate:nil cancelButtonTitle:@"#jolo" otherButtonTitles:nil] show];

话虽如此,Xcode 6.3包括LVVM 6.1,其中包括arm64和浮点数学的变化。请参阅发行说明中的​​Apple LLVM编译器版本6.1部分。 https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html

答案 1 :(得分:0)

Java代码:

public class Division {
    public static void main(String[] args) {
        int a = 42033;
        int b = 360;
        int c = 466;
        double result = a / (double)(b * c);
        System.out.println("Result = " + result);
        double result2 = (a - 1) / (double) (b * c);
        double result3 = (a) / (double) ((b + 1) * c);
        double result4 = (a) / (double) (b * (c + 1));
        System.out.println("Result2 = " + result2);
        System.out.println("Result3 = " + result3);
        System.out.println("Result4 = " + result4);
    }
}

结果:

C:\JavaTools>java Division
Result = 0.2505543633762518
Result2 = 0.250548402479733
Result3 = 0.24986030696800732
Result4 = 0.25001784439685937

可以看出,“错误”结果的解释是,除{OP}所述之外的b值。与算术的精度无关。