Swift में गणना किए गए ग्रिड आकार को पूर्णांक संख्या में बदलने के लिए, पहले पूर्णांकन का नियम चुनें, फिर मान को दर्शाने की क्षमता जाँचने के लिए Int(exactly:) का उपयोग करें। टाइलों से ढके Mac कैनवस के लिए, प्रत्येक अक्ष को ऊपर की ओर पूर्णांकित करें और अंतिम गुणन में ओवरफ़्लो की जाँच करें।
यह लेख डेस्कटॉप ड्रॉइंग टूल के लिए इस गणना को विकसित करता है: आयताकार कैनवस और निश्चित आकार की टाइलों से उसे ढकने के लिए आवश्यक कॉलम, पंक्तियाँ और कुल टाइलें निर्धारित करें। नीचे दिए गए सभी निर्देशांक और संख्याएँ काल्पनिक हैं। ग्रिड कैनवस के अपने मूल बिंदु से शुरू होता है, इसमें कोई अंतराल नहीं है, और बाहरी किनारों पर आंशिक टाइलों की अनुमति है।
ग्रिड के उद्देश्य के अनुसार पूर्णांकन का नियम चुनें
भिन्नात्मक ग्रिड आयाम के लिए पहले नीति चाहिए, फिर प्रकार-रूपांतरण। यदि कैनवस 650 पॉइंट चौड़ा है और प्रत्येक टाइल 64 पॉइंट चौड़ी है, तो गणना किया गया आयाम 650.0 / 64.0, या 10.15625 है। पूरी चौड़ाई ढकने के लिए 11 कॉलम चाहिए। उस चौड़ाई में केवल पूरी तरह समा जाने वाली टाइलें गिनने पर 10 मिलती हैं।
Swift इन अलग-अलग कामों के लिए स्पष्ट पूर्णांकन नियम देता है। .up को धनात्मक अनंत की ओर, .down को ऋणात्मक अनंत की ओर पूर्णांकित करता है, और .towardZero भिन्नात्मक भाग हटा देता है। निकटतम मान तक पूर्णांकन में बराबरी की स्थितियों के लिए अलग नियम हैं। Apple के FloatingPointRoundingRule दस्तावेज़ में ये व्यवहार परिभाषित हैं।
| पाठक का काम | गैर-ऋणात्मक अक्ष आयाम के लिए नियम | 10.15625 का परिणाम |
|---|---|---|
| किनारे की टाइल सहित पूरी सीमा ढकना | .up |
11.0 |
| सीमा के भीतर समाने वाली पूरी टाइलें गिनना | .down |
10.0 |
| निकटतम पूर्णांक आयाम चुनना | .toNearestOrAwayFromZero |
10.0 |
| यह आवश्यक होना कि गणना किया गया आयाम पहले से पूर्णांक हो | कोई पूर्णांकन नहीं; सीधे Int(exactly:) आज़माएँ |
nil |
पूरी सीमा ढकने के लिए .rounded(.up) का उपयोग करें। बिना नियम के .rounded() कॉल करने पर निकटतम मान तक पूर्णांकन चुना जाता है और बराबरी की स्थिति शून्य से दूर पूर्णांकित होती है; इससे इस कैनवस का कुछ हिस्सा खुला रह सकता है। साथ ही, Double को पूर्णांकित करने पर पूर्णांक मान वाला Double ही मिलता है; पूर्णांक में रूपांतरण एक अलग चरण है। Apple के rounded(_:) दस्तावेज़ देखें।
कॉलम और पंक्तियों को अलग-अलग पूर्णांकित करें
मान लें कि काल्पनिक कैनवस क्षैतिज निर्देशांक 20 से 670 तक और ऊर्ध्वाधर निर्देशांक 30 से 440 तक फैला है। इसकी चौड़ाई 650 पॉइंट और ऊँचाई 410 पॉइंट है। प्रति भुजा 64 पॉइंट की वर्गाकार टाइलों के साथ, सीमा ढकने की गणना यह है:
- कॉलम:
ceil(650 / 64) = 11। - पंक्तियाँ:
ceil(410 / 64) = 7। - कुल:
11 × 7 = 77टाइलें।
ये उदाहरणात्मक अंकगणितीय परिणाम हैं, जो बताए गए लेआउट से निकाले गए हैं। कैनवस के क्षेत्रफल को टाइल के क्षेत्रफल से भाग देकर एक बार पूर्णांकित करने पर 66 मिलता है, जो आवश्यक आयताकार व्यवस्था नहीं बताता। हर पंक्ति में 11 टाइल स्थान चाहिए और कैनवस को ऐसी सात पंक्तियाँ चाहिए। दोनों आयामों को पूर्णांकित होने तक अलग-अलग बनाए रखें।
यह सूत्र मानता है कि पहली टाइल कैनवस के मूल बिंदु से शुरू होती है। यदि टाइलें कहीं और से संरेखित ग्रिड की हों, तो शुरुआती ऑफ़सेट बदल सकता है कि आयत कितने सेल से प्रतिच्छेद करता है। केवल चौड़ाई पर आधारित गणना लागू करने से पहले वह संरेखण तय करें।
सीधे पूर्णांक रूपांतरण से काम क्यों नहीं चलता
Swift का सामान्य फ़्लोटिंग-पॉइंट से पूर्णांक प्रारंभकर्ता शून्य की ओर पूर्णांकित करता है। इसलिए, Int(10.15625) से 10 मिलता है। काटने के बाद स्रोत मान को गंतव्य पूर्णांक प्रकार की सीमा में भी आना चाहिए; Apple के अनुसार, सीमा से बाहर का रूपांतरण रनटाइम त्रुटि पैदा कर सकता है। BinaryInteger.init(_:) देखें।
इसलिए, कवरेज आयाम की गणना के लिए उपयोगी क्रम है: Int(exactly: value.rounded(.up)), फिर आवश्यकता पड़ने पर वैकल्पिक स्थिति को संभालना। Apple के अनुसार, Int.init(exactly:) तब nil लौटाता है जब दिया गया फ़्लोटिंग-पॉइंट मान किसी पूर्णांक के रूप में सटीकता से दर्शाया नहीं जा सकता।
यह प्रारंभकर्ता एक सीमित प्रश्न का उत्तर देता है: क्या दिया गया मान सटीक रूप से समा सकता है? यह साबित नहीं करता कि मूल ज्यामिति वैध थी, चुना गया पूर्णांकन नियम लेआउट के अनुकूल है, या इतनी टाइलें बनाना व्यावहारिक है। नीचे दिए गए कार्यान्वयन में ये अलग-अलग जाँचें हैं।
सीमित टाइल संख्या के लिए पूरा Swift प्रोग्राम
निम्न प्रोग्राम निर्देशांकों और आयामों के लिए Double तथा संख्याओं के लिए Int का उपयोग करता है। इसमें सीमाएँ सीमित और गैर-ऋणात्मक, टाइल आयाम सीमित और धनात्मक, तथा ऐप्लिकेशन द्वारा निर्धारित टाइल सीमा धनात्मक होनी चाहिए। यदि कैनवस का कोई भी आयाम शून्य हो, तो खाली ग्रिड मिलता है। उलटी सीमाएँ चुपचाप पुनर्व्यवस्थित करने के बजाय अस्वीकार की जाती हैं।
इस पूरे प्रोग्राम को GridCount.swift नाम से सहेजें और Swift टूलचेन उपलब्ध Mac पर swift GridCount.swift चलाएँ। यह केवल Swift की मानक लाइब्रेरी का उपयोग करता है, इसलिए किसी इम्पोर्ट की आवश्यकता नहीं है। प्रोग्राम अपेक्षित परिणामों के साथ प्रस्तुत है; इसकी जाँच की गई, लेकिन इस शोध के दौरान इसे Swift कंपाइलर से चलाया नहीं गया।
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)")
}
ये जाँचें क्या सुनिश्चित करती हैं
सीमित मानों की जाँच NaN और अनंत को अस्वीकार करती है, ताकि इनमें से कोई भी संख्या बनने से पहले ही रुक जाए। Apple के अनुसार, isFinite दोनों के लिए false होता है। टाइल आयामों का धनात्मक होना शून्य से भाग और ऋणात्मक टाइल आकारों को भी बाहर रखता है।
इनपुट मान्य करने के बाद भी भागफल की अलग से जाँच करना महत्त्वपूर्ण है। कार्यान्वयन गैर-सीमित भागफल को अस्वीकार करता है, और यदि आयाम धनात्मक था तो शून्य भागफल को भी अस्वीकार करता है। यह दूसरी जाँच सुनिश्चित करती है कि अत्यंत छोटा धनात्मक भागफल, जो अंडरफ़्लो होकर शून्य बन जाए, खाली अक्ष के बजाय स्पष्ट विफलता बने। यह उदाहरण की एक जानबूझकर तय की गई सीमा है।
अक्षों के सफल रूपांतरण के बाद भी कुल संख्या की जाँच करनी होती है। दो वैध Int मानों का गुणनफल इस प्रकार की सीमा से बाहर हो सकता है। Apple के multipliedReportingOverflow(by:) दस्तावेज़ के अनुसार, partialValue में पूरा गुणनफल तभी होता है जब overflow false हो। प्रोग्राम गुणनफल का उपयोग करने से पहले इस फ़्लैग की जाँच करता है।
अंतिम maxCells तुलना एक अलग उद्देश्य पूरा करती है: यह ऐप्लिकेशन की सीमा लागू करती है, भले ही अंकगणित सीमा के भीतर हो। उदाहरण के लिए 10,000 का मान कॉलर द्वारा चुनी गई नीति है; यह मेमोरी या ड्रॉइंग प्रदर्शन के बारे में कोई सिफ़ारिश नहीं है। अपनी टाइल के लिए ऐप्लिकेशन वास्तव में क्या बनाता है, उसके अनुसार सीमा चुनें।
पूर्णांक सीमा के पास फ़्लोटिंग-पॉइंट तुलना से बचें
एक आकर्षक जाँच है value <= Double(Int.max) के बाद Int(value)। यह तुलना भ्रमित कर सकती है, क्योंकि पूर्णांक सीमा को फ़्लोटिंग पॉइंट में बदलने पर मान गोल हो सकता है। Apple स्पष्ट रूप से Int से Double.init(_:) को निकटतम संभव निरूपण में रूपांतरण बताता है।
64-बिट टारगेट पर Int.max का मान 9_223_372_036_854_775_807 है। इसे Double में बदलने पर मान 9_223_372_036_854_775_808 हो जाता है, जो एक अधिक है। इस गोल की गई सीमा के बराबर फ़्लोटिंग-पॉइंट मान तुलना पास कर सकता है, जबकि वह पूर्णांक सीमा से बाहर ही रहता है। Apple अपने Int संदर्भ पृष्ठ पर प्लेटफ़ॉर्म की चौड़ाई और पूर्णांक आकार के संबंध का वर्णन करता है।
सीमा का यह उदाहरण अंकगणित समझाने के लिए है, सुझाए गए कैनवस आकार के रूप में नहीं। यह बताता है कि प्रोग्राम मान को दर्शाने की क्षमता की सीधी जाँच के लिए Int(exactly:) से क्यों पूछता है। इससे किसी विशेष पूर्णांक चौड़ाई से जुड़ी अधिकतम संख्या को हार्ड-कोड करने की आवश्यकता भी नहीं पड़ती।
तय करें कि टाइल की सीमा के पास के मानों को कैसे संभालना है
ऊपर की ओर पूर्णांकन वास्तव में संग्रहित मान के अनुसार चलता है। दो से थोड़ा अधिक भागफल के लिए इस कवरेज नीति के तहत तीन टाइलें चाहिए। Swift की nextUp प्रॉपर्टी अगला बड़ा प्रतिनिधेय फ़्लोटिंग-पॉइंट मान देती है, इसलिए (2.0).nextUp.rounded(.up) का मान 3.0 है। इस निकटवर्ती मान का अर्थ Apple के nextUp संदर्भ में दिया गया है।
केवल प्रदर्शित मान को पूर्णांक जैसा दिखाने के लिए मनमाना epsilon न घटाएँ। इससे कवरेज नीति बदल जाती है और किसी छोटे वास्तविक शेष के लिए आवश्यक टाइल हट सकती है। यदि ऐप्लिकेशन जानबूझकर निर्देशांकों को ग्रिड पर स्नैप करता है, तो यह नियम पहले तय करें और स्नैप की गई ज्यामिति से संख्याएँ निकालें। यदि आयाम सटीक पूर्णांक इकाइयों में मिलते हैं, तो संख्या गणना के दौरान उन इकाइयों को बनाए रखने पर विचार करें।
यह उदाहरण यह भी मानता है कि दिए गए निर्देशांकों का घटाव उपयोगी आयाम देता है। अंतिम रूपांतरण सटीक होने पर भी पहले की निर्देशांक गणना में खोया हुआ विवरण वापस नहीं मिल सकता। निर्देशांक का परिमाण लेआउट के अनुकूल रखें और कैनवस तथा टाइल आयामों में एक ही इकाइयों का उपयोग करें।
सही व्यवहार पहचानने वाले मामलों की जाँच करें
सीमा वाले मामलों से अपने रूपांतरण की जाँच करें, खासकर यदि आप पूर्णांकन नीति या खाली ग्रिड के व्यवहार में बदलाव करते हैं। नीचे दिए गए अपेक्षित परिणाम इस प्रोग्राम के बताए अनुबंध के अनुसार हैं; इन्हें Swift में चलाए गए परीक्षणों के परिणाम के रूप में प्रस्तुत नहीं किया गया है।
| काल्पनिक इनपुट | अपेक्षित परिणाम |
|---|---|
कैनवस 650 × 410, टाइलें 64 × 64, सीमा 10_000 |
11 कॉलम, 7 पंक्तियाँ, 77 टाइलें |
कैनवस 128 × 128, टाइलें 64 × 64, सीमा 10_000 |
2 कॉलम, 2 पंक्तियाँ, 4 टाइलें |
कैनवस 129 × 128, टाइलें 64 × 64, सीमा 10_000 |
3 कॉलम, 2 पंक्तियाँ, 6 टाइलें |
| कैनवस का कोई भी आयाम शून्य; अन्य इनपुट वैध | कुल शून्य वाली खाली ग्रिड |
| ऋणात्मक आयाम, शून्य टाइल आयाम या गैर-सीमित इनपुट | invalidInput |
| धनात्मक आयाम को टाइल से भाग देने पर शून्य या अनंत मिले | unrepresentableAxis |
ऊपर की ओर पूर्णांकित अक्ष Int में न समा सके |
unrepresentableAxis |
| वैध अक्ष संख्याओं का गुणनफल ओवरफ़्लो करे | countOverflow |
77 टाइलों वाले उदाहरण में सीमा 50 हो |
exceedsLimit |
इस Mac कैनवस कार्य के लिए, हर अक्ष की गणना होने तक ज्यामिति को फ़्लोटिंग पॉइंट में रखें, आंशिक किनारी टाइलें शामिल करने के लिए ऊपर की ओर पूर्णांकित करें, और Int(exactly:) के ज़रिए रूपांतरित करें। फिर ग्रिड बनाने से पहले गुणनफल और ऐप्लिकेशन की सीमा को मान्य करें। यह क्रम गणना किए गए आयामों को स्पष्ट और समीक्षा योग्य विफलता व्यवहार वाली संख्या में बदलता है।
स्रोत
- FloatingPointRoundingRule — Apple
- rounded(_:) — Apple
- BinaryInteger.init(_:) — Apple
- Int.init(exactly:) — Apple
- isFinite — Apple
- multipliedReportingOverflow(by:) — Apple
- Double.init(_:) — Apple
- Int — Apple
- nextUp — Apple