Avatar ·

Форматирование чисел с плавающей точкой: спецификатор точности в Swift

Всем привет! Я только начал изучать Swift и столкнулся с проблемой при форматировании чисел с плавающей точкой. Мне нужно вывести значение числа Пи (3.1415926535) с разной точностью: например, 2 знака после запятой, 3 знака и так далее. В других языках (C, Java) я помню, что можно использовать что-то вроде `printf("%.2f", pi)` или `String.format("%.2f", pi)`. Но в Swift я не могу найти эквивалент. Пробовал писать так: ```swift let pi = 3.1415926535 print("\(pi)") // выводит 3.1415926535 print("\(pi, specifier: "%.2f")") // не работает ``` И так: ```swift let formatted = String(format: "%.2f", pi) // выводит 3.14 ``` Это работает, но я слышал, что в Swift есть более современный способ. Подскажите, как правильно форматировать числа с плавающей точкой с заданной точностью? Нужно ли использовать старый `String(format:)` или есть что-то встроенное в Swift? Заранее спасибо! <<>>

Использование String(format:) и современных возможностей Swift

Ты абсолютно прав, что String(format:) работает. Это наследие из Objective-C и C, и оно вполне корректно используется в Swift. Однако Swift предлагает более элегантные и типобезопасные способы форматирования чисел. Давай разберём все возможные подходы.

1. Классический String(format:)

Самый простой и понятный способ, если ты привык к printf-стилю:

let pi = 3.1415926535
let twoDecimals = String(format: "%.2f", pi)   // "3.14"
let threeDecimals = String(format: "%.3f", pi) // "3.142"
let fourDecimals = String(format: "%.4f", pi)  // "3.1416"
print(twoDecimals) // Вывод: 3.14
  • %.2f — 2 знака после запятой (округление).
  • %.0f — без дробной части (целое).
  • %6.2f — минимальная ширина 6 символов, 2 знака после запятой.

2. Современный способ: NumberFormatter

Этот подход более гибкий и учитывает локаль пользователя. Рекомендуется для UI (отображение цен, процентов):

import Foundation

let pi = 3.1415926535

let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
formatter.locale = Locale.current // Учитывает региональные настройки

if let formatted = formatter.string(from: NSNumber(value: pi)) {
    print(formatted) // "3.14" (или "3,14" для некоторых локалей)
}
  • maximumFractionDigits — максимальное количество знаков после запятой.
  • minimumFractionDigits — минимальное (дополнит нулями, если нужно).
  • Можно настроить разделители тысяч, валюту и т.д.

3. Использование FloatingPoint протокола (Swift 5.5+)

Начиная с iOS 15 / macOS 12, можно использовать метод formatted() на числах:

import Foundation

let pi = 3.1415926535
let formatted = pi.formatted(.number.precision(.fractionLength(2)))
print(formatted) // "3.14"

Это самый «свифтовый» способ. Он полностью типобезопасен и читаем:

// Другие примеры:
let percent = 0.85
let percentFormatted = percent.formatted(.percent.precision(.fractionLength(0)))
print(percentFormatted) // "85%"

let currency = 1234.5
let currencyFormatted = currency.formatted(.currency(code: "USD"))
print(currencyFormatted) // "$1,234.50"

4. Интерполяция строк с specifier (Swift 5.0+)

Ты почти угадал! В Swift можно использовать интерполяцию с явным указанием спецификатора:

let pi = 3.1415926535
print("\(pi, specifier: "%.2f")") // "3.14"

Это работает, если импортировать Foundation (или UIKit/SwiftUI). Синтаксис немного необычный, но вполне валидный.

Итог

  • Быстро и просто: String(format: "%.2f", pi).
  • Для UI и локализации: NumberFormatter.
  • Современно (iOS 15+): pi.formatted(.number.precision(.fractionLength(2))).
  • Интерполяция: "\(pi, specifier: "%.2f")".

Выбирай тот, который лучше подходит под твою задачу. Если ты пишешь под старые версии iOS — используй String(format:) или NumberFormatter.

<<>>

Альтернативный подход: округление с помощью round() и Decimal

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

let pi = 3.1415926535
let rounded = (pi * 100).rounded() / 100 // 3.14
print(rounded) // 3.14

Однако этот способ может давать погрешности из-за двоичного представления чисел с плавающей точкой. Для финансовых расчётов лучше использовать Decimal:

import Foundation

let pi = Decimal(string: "3.1415926535")!
var rounded = Decimal()
NSDecimalRound(&rounded, &pi, 2, .plain) // округление до 2 знаков
print(rounded) // 3.14

Этот подход гарантирует точность, так как Decimal работает с десятичной арифметикой. Комбинируй его с NumberFormatter для вывода:

let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
let result = formatter.string(from: rounded as NSNumber)!
print(result) // "3.14"

Используй этот метод, если точность критична (например, деньги, научные расчёты).