2015-11-18 7 views
1

Я пытаюсь точно представлять числа с плавающей точкой в ​​Swift. Предположим, что у нас есть номер let doubleNumber = 16.756. Проблема в том, что фактическое число - это что-то вроде 16.7560009. Более того, на другом телефоне это, например, 16.7559991 из-за недостатков процессора. Арифметика с фиксированной точкой должна быть ответом на такие проблемы, но я понятия не имею, как ее решить в Swift. Честно говоря, ни на других языках. Итак, как мне создать фиксированные представления чисел с плавающей запятой в Swift?представление чисел с плавающей точкой в ​​Swift

Причина, по которой я спрашиваю, заключается в том, что при правильной имитации физики через устройства крошечные различия в значении числа с плавающей запятой могут привести к совершенно различным физическим симуляциям.

+0

Что вы на самом деле пытаетесь достигать? В чем проблема, которую вы пытаетесь решить? Вам нужно точно представлять 1.0/3.0? – gnasher729

+0

Я отредактировал мой вопрос. – brumbrum

+0

«Я пытаюсь точно представлять числа с плавающей запятой в Swift». - Эти типы Float и Double уже делают это. Вы вводите в заблуждение числа с плавающей запятой с действительными числами? –

ответ

3

Цифры, которые вы указали, указывают на то, что вы используете Float, а не Double. Float имеет точность примерно 6 цифр, Double - около 15. И помните, что CGFloat - это Float или Double, поэтому не используйте это.

Swift использует стандартную арифметику IEEE 754 с плавающей запятой. Между разными процессорами не должно быть разницы, если вы используете Double последовательно.

Теперь очень важный момент: если небольшие различия между арифметикой с плавающей запятой на разных процессорах производят совершенно разные симуляции, то ни симуляция не имеет ничего общего с реальностью и поэтому совершенно бесполезна. Или оба они показывают один из многих возможных результатов, а затем снова не имеет значения, какой из них вы показываете.

-1

смешной эксперимент

import Foundation 

let f1: Float = 0x1p-149 
f1.isZero      // false 
let f0: Float = 0x1p-150 
f0.isZero      // true 
Float(f1/2) == Float(f1/3) // true ??? what ??? f1 is zero? 

let d1 = 0x1p-1074 
d1.isZero      // false 
let d0 = 0x1p-1075 
d0.isZero      // true 
d1/2 == d1/3    // true 

print("value of Float next to 0 is \(f1) or as Double \(Double(f1))") 
print("value of Double next to 0 is \(d1)") 

/* 

value of Float next to 0 is 1.4013e-45 or as Double 1.40129846432482e-45 
value of Double next to 0 is 4.94065645841247e-324 

*/ 

я рекомендую для всех, кому необходимо выполнять вычисления с плавающей точки What Every Computer Scientist Should Know About Floating-Point Arithmetic

один пример того, как правильный алгоритм может уменьшить ошибку

import Foundation 

var arr: [Float] = [] 
for i in 0...100 { 
    arr.append(Float(random())) 
} 

let sum1 = arr.reduce(0.0) { $0 + $1 } 

var sum2 = arr[0] 
var c:Float = 0.0 
for j in 1..<arr.count { 
    let y: Float = arr[j] - c 
    let t: Float = sum2 + y 
    c = t - sum2 - y 
    sum2 = t 
} 
print(sum1, sum2, "and the 'small' difference is:", sum2 - sum1) 
// 1.18466e+11 1.18466e+11 and the 'small' difference is: 8192.0 

// what do you thing, which one is more precise ? 
// sum1 or sum2 ???? 

// lets try the same with naive Double approach 
let sum3 = arr.map{ Double($0) }.reduce(0.0) { $0 + $1 } 
print(Double(sum1)-sum3) // -11268.0 
print(Double(sum2)-sum3) // -3076.0 
+1

Не могли бы вы добавить некоторые детали, почему это должно работать? Кодовые ответы не очень полезны и подлежат удалению. – Cristik

+0

@Cristik это не ответ, как выполнить арифметику с фиксированной точкой. эти фрагменты могут отвечать на вопросы, например, почему моя итерация никогда не прекращалась или не встречалась. посмотрите на строку d1/2 == d1/3 истинно, даже если d1 (как вы можете видеть в распечатке) НЕ равен – user3441734

+1

, в этом случае обновите ответ и добавьте пояснения относительно результатов эксперимента в текущей форме ответ не очень полезен для искателя. – Cristik

Смежные вопросы