Untuk menukar saiz grid terhitung kepada bilangan integer dalam Swift, pilih dahulu kaedah pembundaran, kemudian gunakan Int(exactly:) untuk menyemak kebolehwakilan. Bagi kanvas Mac yang diliputi jubin, bundarkan setiap paksi ke atas dan semak pendaraban akhir untuk limpahan.

Artikel ini menghuraikan pengiraan tersebut untuk alat lukisan desktop: berdasarkan kanvas segi empat tepat dan jubin bersaiz tetap, tentukan bilangan lajur, baris dan jumlah jubin yang diperlukan untuk meliputinya. Semua koordinat dan bilangan di bawah ialah data sintetik. Grid bermula pada titik asal kanvas itu sendiri, tidak mempunyai jarak antara jubin dan membenarkan jubin separa di bahagian tepi.

Pilih kaedah pembundaran berdasarkan tujuan grid

Dimensi grid pecahan memerlukan dasar sebelum penukaran jenis. Jika lebar kanvas ialah 650 titik dan lebar setiap jubin ialah 64 titik, dimensi terhitung ialah 650.0 / 64.0, atau 10.15625. Untuk meliputi seluruh lebar, diperlukan 11 lajur. Jika hanya mengira jubin penuh yang muat dalam lebar itu, hasilnya 10.

Swift menyediakan kaedah pembundaran yang jelas untuk tugas yang berbeza ini. .up membundarkan ke arah infiniti positif, .down ke arah infiniti negatif dan .towardZero membuang bahagian pecahan. Pembundaran kepada nilai terdekat mempunyai kaedah berasingan untuk nilai seri. Tingkah laku ini ditakrifkan dalam dokumentasi FloatingPointRoundingRule Apple.

Tugas pembaca Kaedah untuk dimensi paksi bukan negatif Hasil untuk 10.15625
Meliputi keseluruhan kawasan, termasuk jubin di tepi .up 11.0
Mengira jubin penuh yang muat dalam kawasan .down 10.0
Memilih dimensi nombor bulat yang paling hampir .toNearestOrAwayFromZero 10.0
Memerlukan dimensi terhitung sudah berupa integer Tiada pembundaran; cuba Int(exactly:) secara langsung nil

Untuk tugas meliputi kawasan, gunakan .rounded(.up). Memanggil .rounded() tanpa kaedah akan memilih pembundaran terdekat dengan nilai seri dibundarkan menjauhi sifar, yang boleh menyebabkan sebahagian kanvas ini tidak diliputi. Selain itu, pembundaran Double menghasilkan Double yang nilainya nombor bulat; penukaran integer ialah langkah yang berasingan. Lihat dokumentasi rounded(_:) Apple.

Bundarkan lajur dan baris secara berasingan

Anggap kanvas sintetik terbentang dari koordinat mendatar 20 hingga 670 dan koordinat menegak 30 hingga 440. Lebarnya 650 titik dan tingginya 410 titik. Dengan jubin segi empat sama yang setiap sisinya berukuran 64 titik, pengiraan liputan ialah:

  • Lajur: ceil(650 / 64) = 11.
  • Baris: ceil(410 / 64) = 7.
  • Jumlah: 11 × 7 = 77 jubin.

Ini ialah hasil aritmetik ilustrasi yang diperoleh daripada susun atur yang dinyatakan. Membahagikan luas kanvas dengan luas jubin dan membundarkan sekali sahaja menghasilkan 66, yang tidak menggambarkan susunan segi empat tepat yang diperlukan. Setiap baris memerlukan 11 kedudukan jubin, dan kanvas memerlukan tujuh baris sedemikian. Kekalkan kedua-dua dimensi itu sehingga kedua-duanya selesai dibundarkan.

Formula ini mengandaikan jubin pertama bermula pada titik asal kanvas. Jika jubin sebaliknya berada dalam grid yang dijajarkan pada tempat lain, anjakan titik mula boleh mengubah bilangan sel yang bersilang dengan segi empat tepat itu. Tetapkan penjajaran tersebut sebelum menggunakan pengiraan berdasarkan lebar sahaja.

Mengapa penukaran integer secara langsung tidak mencukupi

Pemula penukaran biasa Swift daripada titik terapung kepada integer membundarkan ke arah sifar. Oleh itu, Int(10.15625) menghasilkan 10. Nilai sumber selepas pemotongan juga mesti muat dalam jenis integer destinasi; Apple mendokumenkan bahawa penukaran di luar julat boleh menyebabkan ralat semasa jalanan. Lihat BinaryInteger.init(_:).

Oleh itu, urutan yang sesuai untuk dimensi liputan terhitung ialah Int(exactly: value.rounded(.up)), diikuti pengendalian pilihan. Apple mendokumenkan bahawa Int.init(exactly:) mengembalikan nil apabila nilai titik terapung yang diberikan tidak dapat diwakilkan dengan tepat sebagai integer.

Pemula ini menjawab soalan yang khusus: adakah nilai yang diberikan ini muat dengan tepat? Ia tidak menentukan sama ada geometri asal sah, sama ada kaedah pembundaran yang dipilih sesuai untuk susun atur, atau sama ada praktikal untuk mencipta jubin sebanyak itu. Semua perkara itu memerlukan semakan berasingan dalam pelaksanaan di bawah.

Program Swift lengkap untuk bilangan jubin yang dihadkan

Program berikut menggunakan Double untuk koordinat dan dimensi serta Int untuk bilangan. Program ini memerlukan rentang yang terhingga dan bukan negatif, dimensi jubin yang terhingga dan positif serta had jubin yang ditentukan aplikasi dan bernilai positif. Kanvas dengan mana-mana rentang bersamaan sifar menghasilkan grid kosong. Sempadan yang diterbalikkan akan ditolak dan bukannya disusun semula secara senyap.

Simpan program lengkap ini sebagai GridCount.swift dan jalankannya dengan swift GridCount.swift pada Mac yang mempunyai toolchain Swift. Program ini hanya menggunakan pustaka standard Swift, jadi tiada import diperlukan. Program ini dipaparkan bersama hasil yang dijangka; ia telah diperiksa tetapi tidak dijalankan menggunakan pengkompil Swift semasa penyelidikan ini.

enum GridError: Error {
    case invalidInput
    case unrepresentableAxis
    case countOverflow
    case exceedsLimit
}

struct GridCount {
    let columns: Int
    let rows: Int
    let total: Int
}

func coveringAxis(extent: Double, tile: Double) throws -> Int {
    guard extent.isFinite, extent >= 0,
          tile.isFinite, tile > 0 else {
        throw GridError.invalidInput
    }
    if extent == 0 { return 0 }

    let quotient = extent / tile
    guard quotient.isFinite, quotient > 0,
          let count = Int(exactly: quotient.rounded(.up)),
          count > 0 else {
        throw GridError.unrepresentableAxis
    }
    return count
}

func coveringGrid(
    width: Double,
    height: Double,
    tileWidth: Double,
    tileHeight: Double,
    maxCells: Int
) throws -> GridCount {
    guard width.isFinite, width >= 0,
          height.isFinite, height >= 0,
          tileWidth.isFinite, tileWidth > 0,
          tileHeight.isFinite, tileHeight > 0,
          maxCells > 0 else {
        throw GridError.invalidInput
    }

    if width == 0 || height == 0 {
        return GridCount(columns: 0, rows: 0, total: 0)
    }

    let columns = try coveringAxis(extent: width, tile: tileWidth)
    let rows = try coveringAxis(extent: height, tile: tileHeight)
    let product = columns.multipliedReportingOverflow(by: rows)

    guard !product.overflow else {
        throw GridError.countOverflow
    }
    guard product.partialValue <= maxCells else {
        throw GridError.exceedsLimit
    }

    return GridCount(
        columns: columns,
        rows: rows,
        total: product.partialValue
    )
}

let left: Double = 20
let right: Double = 670
let top: Double = 30
let bottom: Double = 440

 do {
    let grid = try coveringGrid(
        width: right - left,
        height: bottom - top,
        tileWidth: 64,
        tileHeight: 64,
        maxCells: 10_000
    )
    print("columns=\(grid.columns), rows=\(grid.rows), total=\(grid.total)")
    // Expected: columns=11, rows=7, total=77
} catch {
    print("Grid calculation failed: \(error)")
}

Fungsi semakan

Semakan nilai terhingga menolak NaN dan infiniti sebelum salah satu daripadanya boleh menjadi bilangan. Apple menyatakan bahawa isFinite bernilai false untuk kedua-duanya. Syarat dimensi jubin positif juga menolak pembahagian dengan sifar dan saiz jubin negatif.

Menyemak hasil bahagi secara berasingan tetap penting walaupun input telah disahkan. Pelaksanaan ini menolak hasil bahagi bukan terhingga dan menolak nilai sifar apabila rentangnya positif. Semakan kedua itu menjadikan hasil bahagi positif yang amat kecil tetapi mengalami limpahan ke bawah menjadi sifar sebagai kegagalan yang jelas, bukannya paksi kosong. Ini ialah had yang disengajakan dalam contoh ini.

Setiap penukaran paksi yang berjaya masih meninggalkan jumlah untuk disemak. Dua nilai Int yang sah boleh menghasilkan hasil darab di luar julat jenis tersebut. Dokumentasi multipliedReportingOverflow(by:) Apple menyatakan bahawa partialValue mengandungi hasil darab penuh hanya apabila overflow bernilai false. Program ini menyemak bendera itu sebelum menggunakan hasil darab.

Perbandingan akhir maxCells mempunyai tujuan yang berbeza: menguatkuasakan had aplikasi walaupun pengiraan tidak melimpah. Nilai ilustrasi 10,000 ialah dasar yang dipilih oleh pemanggil, bukannya saranan tentang prestasi memori atau lukisan. Pilih had berdasarkan perkara yang benar-benar dicipta oleh aplikasi anda untuk setiap jubin.

Elakkan semakan julat titik terapung pada sempadan integer

Semakan yang kelihatan menarik ialah value <= Double(Int.max) diikuti Int(value). Perbandingan itu boleh mengelirukan kerana penukaran had integer kepada titik terapung mungkin membundarkan nilainya. Apple secara jelas menerangkan Double.init(_:) daripada Int sebagai penukaran kepada perwakilan terdekat yang mungkin.

Pada sasaran 64-bit, Int.max ialah 9_223_372_036_854_775_807. Penukarannya kepada Double dibundarkan kepada 9_223_372_036_854_775_808, iaitu satu lebih besar. Nilai titik terapung yang sama dengan had yang telah dibundarkan itu akan melepasi perbandingan sedangkan nilainya masih di luar julat integer. Apple mendokumenkan hubungan antara lebar platform dengan saiz integer pada halaman rujukan Int.

Contoh sempadan ini ialah ilustrasi aritmetik, bukannya saiz kanvas yang dicadangkan. Contoh ini menjelaskan sebab program meminta Int(exactly:) melakukan semakan kebolehwakilan secara langsung. Cara ini juga mengelakkan pengekodan keras bilangan maksimum yang terikat pada lebar integer tertentu.

Tentukan cara mengendalikan nilai yang hampir dengan sempadan jubin

Pembundaran ke atas mengikut nilai yang benar-benar disimpan. Hasil bahagi yang sedikit melebihi dua memerlukan tiga jubin mengikut dasar liputan ini. Sifat nextUp Swift menyediakan nilai titik terapung boleh wakil seterusnya yang lebih besar, jadi (2.0).nextUp.rounded(.up) ialah 3.0. Maksud nilai bersebelahan itu didokumenkan dalam rujukan nextUp Apple.

Jangan tolak epsilon sewenang-wenangnya semata-mata untuk menjadikan nilai yang dipaparkan kelihatan seperti nombor bulat. Tindakan itu mengubah dasar liputan dan boleh menggugurkan jubin yang diperlukan untuk baki kecil yang sebenar. Jika aplikasi sengaja melaraskan koordinat ke grid, tetapkan peraturan pelarasan itu pada peringkat huluan dan kira bilangan daripada geometri yang telah dilaraskan. Jika dimensi berasal daripada unit integer yang tepat, pertimbangkan untuk mengekalkan unit itu sepanjang pengiraan bilangan.

Contoh ini juga mengandaikan bahawa penolakan koordinat yang diberikan menghasilkan rentang yang berguna. Penukaran akhir yang tepat tidak dapat memulihkan butiran yang telah hilang dalam pengiraan koordinat terdahulu. Pastikan magnitud koordinat sesuai untuk susun atur dan gunakan unit yang sama untuk dimensi kanvas dan jubin.

Semak kes yang membezakan tingkah laku yang betul

Gunakan kes sempadan untuk mengesahkan penyesuaian anda, terutamanya jika anda mengubah dasar pembundaran atau tingkah laku grid kosong. Hasil dijangka berikut menepati kontrak yang dinyatakan oleh program ini; hasil ini bukan laporan pelaksanaan ujian Swift.

Input sintetik Hasil dijangka
Kanvas 650 × 410, jubin 64 × 64, had 10_000 11 lajur, 7 baris, 77 jubin
Kanvas 128 × 128, jubin 64 × 64, had 10_000 2 lajur, 2 baris, 4 jubin
Kanvas 129 × 128, jubin 64 × 64, had 10_000 3 lajur, 2 baris, 6 jubin
Mana-mana rentang kanvas bernilai sifar; input lain sah Grid kosong dengan jumlah sifar
Rentang negatif, dimensi jubin sifar atau input bukan terhingga invalidInput
Rentang positif dibahagi dengan jubin menghasilkan sifar atau infiniti unrepresentableAxis
Paksi yang dibundarkan ke atas tidak muat dalam Int unrepresentableAxis
Bilangan paksi yang sah tetapi hasil darabnya melimpah countOverflow
Contoh 77 jubin dengan had 50 exceedsLimit

Untuk tugas kanvas Mac ini, kekalkan geometri dalam titik terapung sehingga setiap paksi selesai dikira, bundarkan ke atas untuk memasukkan jubin separa di tepi dan lakukan penukaran melalui Int(exactly:). Kemudian sahkan pendaraban dan had aplikasi sebelum mencipta grid. Urutan ini menukar dimensi terhitung kepada bilangan dengan tingkah laku kegagalan yang jelas dan mudah disemak.

Sumber