Резюме
Арифметика с плавающей точкой точный, к сожалению, он не очень хорошо сочетается с нашим обычным представлением числа base-10, так что получается, что мы часто даем ему ввод, который немного от того, что мы написали.
Даже простые числа, такие как 0.01, 0.02, 0.03, 0.04 ... 0.24, не представляются точно как двоичные дроби, даже если в мантиссе были тысячи бит точности, даже если у вас были миллионы. Если вы отсчитываете с шагом 0,01, пока вы не достигнете 0,25, вы получите первую фракцию (в этой последовательности), представленную в base10 и base2. Но если вы попытались использовать FP, ваш 0,01 был бы слегка отключен, поэтому единственный способ добавить 25 из них до хорошего точного 0.25 потребовал бы длинной цепи причинности, включающей защитные биты и округление.
Мы постоянно даем аппарату FP что-то вроде простого в базе 10, но это повторяющаяся фракция в базе 2.
Как это произошло?
Когда мы пишем в десятичной форме, каждая дробь является рациональным числом форма
& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; x / (2n + 5n).
В двоичном выражении мы получаем только член 2n , то есть:
& nbsp ; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; & NBSP; x / 2n
Итак, в десятичной форме мы не можем представлять 1/3. Поскольку база 10 включает в себя 2 как простой коэффициент, каждое число, которое мы можем записать как двоичную дробь , также может быть записано в виде базовой дроби. Однако вряд ли что-либо, что мы пишем как base10, представляется в двоичном виде. В диапазоне от 0,01, 0,02, 0,03 ... 0,99 только цифры три могут быть представлены в нашем формате FP: 0,25, 0,50 и 0,75, поскольку они равны 1/4, 1/2, и 3/4 - все числа с простым множителем, использующим только 2n-член.
В базе 10 мы не можем представлять 1/3. Но в двоичном коде мы не можем делать 1/10 или 1/3.
Так что, хотя каждая двоичная дробь может быть записана в десятичной системе, обратное неверно. И фактически большинство десятичных дробей повторяются в двоичном формате.
Работа с ним
Разработчикам обычно дают указание & Lt; epsilon , лучшим советом может быть округление до целочисленных значений (в библиотеке C: round () и roundf (), т. е. оставаться в формате FP), а затем сравнивать. Округление до определенной длины десятичной дроби решает большинство проблем с выходом.
Кроме того, при реальных проблемах с хрустом (проблемы, которые FP был изобретен на ранних, ужасно дорогих компьютерах) физические константы вселенной и все другие измерения известны только относительно небольшому числу значимых цифр, поэтому все пространство проблем было «неточным» в любом случае. FP «точность» не является проблемой в этом виде приложений.
Вся проблема действительно возникает, когда люди пытаются использовать FP для подсчета бобов. Это работает для этого, но только если вы придерживаетесь интегральных значений, какой вид поражает смысл его использования. Вот почему у нас есть все эти библиотеки программного обеспечения с десятичной дроби.
Мне нравится ответ на пиццу от Chris , потому что он описывает фактическую проблему, а не только обычная ручная работа о «неточности». Если бы FP были просто «неточными», мы могли бы исправить , что и сделали бы это несколько десятилетий назад. Причина, по которой у нас нет, - это то, что формат FP компактен и быстр, и это лучший способ хрустить множество чисел. Кроме того, это наследие космической эры и гонки вооружений и ранние попытки решить большие проблемы с очень медленными компьютерами с использованием небольших систем памяти. (Иногда отдельные магнитные сердечники для 1-битного хранилища, но это другая история. )
Заключение
Если вы просто считаете бобы в банке, программные решения, которые используют представления десятичной строки, в первую очередь работают отлично. Но вы не можете делать квантовую хромодинамику или аэродинамику таким образом.
Чтобы получить представление о клавиатуре, сам код довольно прост. Код, который вы опубликовали, неверен, попробуйте это (обратите внимание, что вы должны подключить textField
к UITextField
в раскадровке):
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 44))
customView.backgroundColor = UIColor.red
textField.inputAccessoryView = customView
}
Изменения в вашем коде:
accessoryView
height var myView: customUIView
& amp; все viewDidLoad()
переопределяют xcode 9.2, swift 4
KeyboardToolbarButton
blockquote>import UIKit enum KeyboardToolbarButton: Int { case done = 0 case cancel case back, backDisabled case forward, forwardDisabled func createButton(target: Any?, action: Selector?) -> UIBarButtonItem { var button: UIBarButtonItem! switch self { case .back: button = UIBarButtonItem(title: "back", style: .plain, target: target, action: action) case .backDisabled: button = UIBarButtonItem(title: "back", style: .plain, target: target, action: action) button.isEnabled = false case .forward: button = UIBarButtonItem(title: "forward", style: .plain, target: target, action: action) case .forwardDisabled: button = UIBarButtonItem(title: "forward", style: .plain, target: target, action: action) button.isEnabled = false case .done: button = UIBarButtonItem(title: "done", style: .plain, target: target, action: action) case .cancel: button = UIBarButtonItem(title: "cancel", style: .plain, target: target, action: action) } button.tag = rawValue return button } static func detectType(barButton: UIBarButtonItem) -> KeyboardToolbarButton? { return KeyboardToolbarButton(rawValue: barButton.tag) } }
KeyboardToolbar
blockquote>import UIKit protocol KeyboardToolbarDelegate: class { func keyboardToolbar(button: UIBarButtonItem, type: KeyboardToolbarButton, tappedIn toolbar: KeyboardToolbar) } class KeyboardToolbar: UIToolbar { weak var toolBarDelegate: KeyboardToolbarDelegate? init() { super.init(frame: .zero) barStyle = UIBarStyle.default isTranslucent = true sizeToFit() isUserInteractionEnabled = true } func setup(leftButtons: [KeyboardToolbarButton], rightButtons: [KeyboardToolbarButton]) { let leftBarButtons = leftButtons.map { (item) -> UIBarButtonItem in return item.createButton(target: self, action: #selector(buttonTapped)) } let rightBarButtons = rightButtons.map { (item) -> UIBarButtonItem in return item.createButton(target: self, action: #selector(buttonTapped(sender:))) } let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) setItems(leftBarButtons + [spaceButton] + rightBarButtons, animated: false) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } @objc func buttonTapped(sender: UIBarButtonItem) { if let type = KeyboardToolbarButton.detectType(barButton: sender) { toolBarDelegate?.keyboardToolbar(button: sender, type: type, tappedIn: self) } } }
Полный пример использования
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. createTextField(frame: CGRect(x: 50, y: 50, width: 200, height: 40), leftButtons: [.backDisabled, .forward], rightButtons: [.cancel]) createTextField(frame: CGRect(x: 50, y: 120, width: 200, height: 40), leftButtons: [.back, .forwardDisabled], rightButtons: [.done]) } private func createTextField(frame: CGRect, leftButtons: [KeyboardToolbarButton] = [], rightButtons: [KeyboardToolbarButton] = []) { let textField = UITextField(frame: frame) textField.borderStyle = .roundedRect let toolbar = KeyboardToolbar() toolbar.toolBarDelegate = self toolbar.setup(leftButtons: leftButtons, rightButtons: rightButtons) textField.inputAccessoryView = toolbar view.addSubview(textField) } } extension ViewController: KeyboardToolbarDelegate { func keyboardToolbar(button: UIBarButtonItem, type: KeyboardToolbarButton, tappedIn toolbar: KeyboardToolbar) { print("Tapped button type: \(type)") } }
Результаты