1.現象:
因APP業務需要,從后臺端取得軌跡點的string,包含一千及以上個經緯度坐標點,數值精度為小數點后六位,string轉number類型時,精度仍然正確,又number轉double時,精度出現變化,小數點第六位出現失真,例1.123456->1.123455999999或者1.123456000001這樣子。
2.解決辦法:
一開始其實是用的float類型,因為6位小數float類型也足夠了,轉成double仍然沒解決問題。查了下,由于double也就是浮點型類型在計算機中的存在方式導致的此現象,無解。提工單給高德地圖,也無解,距離計算只接受double類型,也沒有很好的辦法保證精度。
3.doble類型不穩定的解決辦法,(用于計算
1.與后臺等其他端的數據交互就用string格式;
2.本地數據計算,非常精確的使用十進制numberNSDecimalNumber
格式來計算。
以下內容來自引用原文鏈接
NSDecimalNumber
類型的的計算
NSDecimalNumber
-十進制數,可以有小數點,可以是正負數。繼承于NSNumber,常用于精確的數值計算,比如金融等方面。
-
+ (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag;
mantissa:長整形;exponent:指數;flag:正負數。
-NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO]; //12.75
subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:2 isNegative:YES]; //-127500
-
+ (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)dcm;
將C語言NSDecimal類型轉成一個十進制數。
NSDecimalNumber *subtotalAmount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO]; //12.75
NSDecimal decimalValue = [subtotalAmount decimalValue];
/**
* 數據結構:
(NSDecimal) decimalValue = {
_exponent = -2
_length = 1
_isNegative = 0
_isCompact = 1
_reserved = 0
_mantissa = ([0] = 1275, [1] = 0, [2] = 0, [3] = 0, [4] = 0, [5] = 0, [6] = 0, [7] = 0)
*/
subtotalAmount = [NSDecimalNumber decimalNumberWithDecimal:decimalValue]; //12.75
-
+ (NSDecimalNumber *)decimalNumberWithString:(nullable NSString *)numberValue;
將字符串轉成一個十進制數。
NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithString:@"-12.74"]; //-12.74
discountAmount = [NSDecimalNumber decimalNumberWithString:@"127.4"]; //127.4
-
+ (NSDecimalNumber *)decimalNumberWithString:(nullable NSString *)numberValue locale:(nullable id)locale;
這個有點復雜,locale代表一種格式,就像date的格式化一樣。這里的locale可以傳遞兩種格式
NSDictionary類型:
NSDictionary *locale = [NSDictionary dictionaryWithObject:@"," forKey:NSLocaleDecimalSeparator]; //以","當做小數點格式
NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithString:@"123,40" locale:locale]; //123.4
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"fr_FR"]; //法國數據格式,法國的小數點是','逗號
NSDecimalNumber *discountAmount = [NSDecimalNumber decimalNumberWithString:@"123,40" locale:locale]; //123.4
+(NSDecimalNumber *)zero; //0
+(NSDecimalNumber *)one; //1
+(NSDecimalNumber *)minimumDecimalNumber;
//-3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+(NSDecimalNumber *)maximumDecimalNumber;
//3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+(NSDecimalNumber *)notANumber;
//非數字,常用于對比,比如:
[[NSDecimalNumber notANumber] isEqualToNumber:myNumber];
- 加法運算
-(NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber;
-(NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
- 減法運算
-(NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber;
-(NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
- 乘法運算
-(NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber;
-(NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
- 除法運算
-(NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber;
-(NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
- a的n次方
-(NSDecimalNumber *)decimalNumberByRaisingToPower:(NSUInteger)power;
-(NSDecimalNumber *)decimalNumberByRaisingToPower:(NSUInteger)power withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
- 指數運算
-(NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power;
-(NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power
withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
- 四舍五入運算
-(NSDecimalNumber *)decimalNumberByRoundingAccordingToBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
- 比較運算
-(NSComparisonResult)compare:(NSNumber *)decimalNumber;
示例
NSDecimalNumber *discount1 = [NSDecimalNumber decimalNumberWithString:@"1.2"];
NSDecimalNumber *discount2 = [NSDecimalNumber decimalNumberWithString:@"1.3"];
NSComparisonResult result = [discount1 compare:discount2];
if (result == NSOrderedAscending) {
NSLog(@"1.2 < 1.3");
} else if (result == NSOrderedSame) {
NSLog(@"1.2 == 1.3");
} else if (result == NSOrderedDescending) {
NSLog(@"1.2 > 1.3");
}
注意:像NSNumber一樣,所有的NSDecimalNumber對象都是不可變額,這意味著在它們創建之后不能改變它們的值
*還有這個博客可以參考下,比較全 *[關于OC中的小數精確計算---NSDecimalNumber]
4. 數據類型的復習
既然都接觸到基本數據類型了 ,順便回憶整理下基本數據類型好了
OC的基本數據類型包括:整型、字符型、浮點型、布爾型、枚舉型。
- 一、整型
整型包含以下幾種類型
1.short(短整型):內存中通常占2字節,即16位,取值范圍-32768 - +32767。
2.int(整型):通常占4字節,取值范圍-2147483648 - 2147483647
3.long(長整型):通常占8字節
4.long long(長整型):通常占8字節
關于內存中占用的字節數,OC中并沒有硬性的規定,只是需要字節數符合以下條件:
short <= int <= long<= long long
// 基本數據類型
int a = 10;
//下面的數已經超出了int的取值范圍,編譯器會提出警告
int b = 10000000000000;
NSLog(@"%d",b);
//而這個數在long long的取值范圍內,所以不會溢出
long long c =1000000000000;
NSLog(@"%lld",c);
//mac系統下輸出各種類型占用的位數
//輸出:short:2 int:4 long:8 long long:8
NSLog(@"short:%lu int:%lu long:%lu long long:%lu",sizeof(short),sizeof(int),sizeof(long),sizeof(long long));
整型有3種進制表示方式:十進制,八進制,十六進制
//八進制,以0開頭
int i8 = 010;
//十進制
int i10 = 10;
//十六進制,以0x或者0X開頭
int i16 = 0x10;
//8 10 16
NSLog(@"%d %d %d",i8,i10,i16);
整型前加上unsigned關鍵字后,將它變成無符號整型,最高位不是符號位,而是數值位。無符號整數不能表示負數,但是表示范圍大了。
short s = 32768;
unsigned short us = 32768;
//輸出-32768,32768,說明正整數表示范圍比原先大了
NSLog(@"%d,%u",s,us);
- 二、字符型
字符型在OC中只占用一個字節,OC字符變量不支持中文字符,字符需要使用’’包起來,char類型也可以看作整型值來使用,它是一個8位無符號整數,取值范圍0-255。
另外可以通過轉義字符表示特殊字符常量:
| 轉義字符 | 說明 |
| --------- | ----- | - 三、浮點型
浮點類型包括float、double和long double,float占用4字節,double占8字節,long double占16字節。
OC中浮點數表示方法有兩種,一種是包含小數點的簡單的浮點數,另一種是科學計數法形式的浮點數
//利用浮點數計算類型取值范圍
int i0 =-1/0.0;
int i1 = 1/0.0;
//輸出:int型取值范圍:-2147483648-2147483647
NSLog(@"int型取值范圍:%d-%d",i0,i1);
- 四、布爾型
OC中BOOL類型有兩個值:YES和NO
BOOL b1 = YES;
if (b1) {
NSLog(@"%d",b1);
}
BOOL b1 = 10;
//輸出: YES: 10
if (b1) {
NSLog(@"YES: %d",b1);
}else{
NSLog(@"NO: %d",b1);
}
BOOL b1 = 768;
//輸出: NO: 0
if (b1) {
NSLog(@"YES: %d",b1);
}else{
NSLog(@"NO: %d",b1);
}
//注意:不要以為所有的非0整數變量賦給BOOL類型就一定得到YES,上面的768的出的就是NO,BOOL類型實質上就是signed char。
- 五、枚舉型
一個變量只有幾種可能的值,這個變量就可以定義為枚舉變量
enum season {spring,summer,fall,winter};
enum season mySeason = spring;
mySeason = summer;
- 六、格式字符
在NSLog函數中我們使用了很多格式字符,如%d,%lu等。我們這里將介紹NSLog支持的格式字符。
原文鏈接 - 取值范圍
為了以后開發中能夠方便查找,并正確的使用數據類型,下面是部分數據類型的取值范圍:
int:-2147483648~2147483647
unsigned int:0~4294967295
short:-32768~32767
unsigned short:0~65535
long: -2147483648~2147483647
unsigned long:0~4294967295