কোনও পূর্ণসংখ্যার বর্গমূলটি পূর্ণসংখ্যা কিনা তা নির্ধারণের দ্রুততম উপায়


1453

আমি longমানটি নিখুঁত বর্গক্ষেত্র কিনা (যেমন এর বর্গমূলটি অন্য একটি পূর্ণসংখ্যা) তা নির্ধারণের দ্রুততম উপায়টি সন্ধান করছি :

  1. বিল্ট-ইন Math.sqrt() ফাংশনটি ব্যবহার করে আমি এটি সহজ উপায়ে করেছি , তবে আমি ভাবছি যে কেবলমাত্র পূর্ণসংখ্যার ডোমেনে নিজেকে সীমাবদ্ধ রেখে দ্রুত এটি করার কোনও উপায় আছে কিনা I'm
  2. একটি লুকআপ টেবিল নিয়ন্ত্রণের অকার্যকর (যেহেতু সেখানে 2 চলেছেন 31.5 পূর্ণসংখ্যার যার বর্গ 2 চেয়ে কম হয় 63 )।

এখানে এখন এটি করা খুব সহজ এবং সোজা উপায়:

public final static boolean isPerfectSquare(long n)
{
  if (n < 0)
    return false;

  long tst = (long)(Math.sqrt(n) + 0.5);
  return tst*tst == n;
}

দ্রষ্টব্য: আমি এই প্রকল্পটি অনেক প্রকল্পের ইউলারের সমস্যায় ব্যবহার করছি । সুতরাং আর কাউকে এই কোডটি বজায় রাখতে হবে না। এবং এই ধরণের মাইক্রো-অপটিমাইজেশন আসলে একটি পার্থক্য তৈরি করতে পারে, যেহেতু চ্যালেঞ্জের একটি অংশ প্রতিটি অ্যালগরিদমকে এক মিনিটেরও কম সময়ে করা এবং এই সমস্যাটি কয়েকটি সমস্যার জন্য কয়েক মিলিয়ন বার বলা প্রয়োজন।


আমি সমস্যার বিভিন্ন সমাধান চেষ্টা করেছি:

  • নিখুঁত পরীক্ষার পরে, আমি খুঁজে পেয়েছি যে যোগ 0.5 ম্যাথ.এসকিআরটি () এর ফলাফল করা কমপক্ষে আমার মেশিনে নয়।
  • ফাস্ট বর্গমূল বিপরীত দ্রুত ছিল, কিন্তু এটি এন> = 410881. তবে ভুল ফল পাওয়া যায়, যেমন দ্বারা প্রস্তাবিত BobbyShaftoe , আমরা এন <410881 জন্য FISR হ্যাক ব্যবহার করতে পারেন।
  • নিউটনের পদ্ধতিটি তুলনায় অনেকটা ধীর ছিল Math.sqrt()। এটি সম্ভবত কারণ Math.sqrt()নিউটনের পদ্ধতির অনুরূপ কিছু ব্যবহার করে তবে এটি হার্ডওয়ারে প্রয়োগ করা হয়েছে যাতে এটি জাবার চেয়ে অনেক দ্রুত। এছাড়াও, নিউটনের পদ্ধতিতে এখনও ডাবলসের প্রয়োজন।
  • একটি পরিবর্তিত নিউটনের পদ্ধতি, যা কয়েকটি কৌশল ব্যবহার করেছিল যাতে কেবলমাত্র পূর্ণসংখ্যার গণিত জড়িত ছিল, ওভারফ্লো এড়াতে কিছু হ্যাকের প্রয়োজন ছিল (আমি চাই এই ফাংশনটি সব ইতিবাচক 64-বিট স্বাক্ষরিত পূর্ণসংখ্যার সাথে কাজ করা উচিত), এবং এটি এখনও ধীর ছিল Math.sqrt()
  • বাইনারি চপ এমনকি ধীর ছিল। এটি বোধগম্য হয় কারণ বাইনারি চপটি গড় একটি 64-বিটের সংখ্যার বর্গমূল খুঁজে পেতে গড়ে 16 টি পাসের প্রয়োজন।
  • জন এর পরীক্ষাগুলি অনুসারে, orস্টেটমেন্টগুলি ব্যবহার করার চেয়ে সি ++ তে দ্রুত হয় switchতবে জাভা এবং সি # তে orএবং এর মধ্যে কোনও পার্থক্য নেই বলে মনে হয় switch
  • আমি একটি অনুসন্ধান সারণীও তৈরি করার চেষ্টা করেছি (boo৪ বুলিয়ান মানগুলির একটি ব্যক্তিগত স্ট্যাটিক অ্যারে হিসাবে)। তারপরে সুইচ বা orস্টেটমেন্টের পরিবর্তে আমি কেবল বলব if(lookup[(int)(n&0x3F)]) { test } else return false;। আমার অবাক করার বিষয়, এটি ধীরে ধীরে (কিছুটা সামান্য) ছিল। এটি জাভাতে অ্যারে বাউন্ডগুলি চেক করা হয় কারণ এটি ।

21
এটি জাভা কোড, যেখানে int == 32 বিট এবং দীর্ঘ == 64 বিট এবং উভয়ই স্বাক্ষরিত।
কিপ

14
@ শ্রীভাস্তা: আমি বড় মূল্যবোধের উপর কিছু পরীক্ষা করেছি (2 ^ 53 এরও বেশি) এবং আপনার পদ্ধতিতে কিছু মিথ্যা ধনাত্মকতা দেয়। প্রথমটির মুখোমুখি হ'ল এন = 9007199326062755, যা নিখুঁত বর্গ নয় তবে এটি হিসাবে ফিরে আসে।
কিপ করুন

37
দয়া করে এটিকে "জন কারম্যাক হ্যাক" বলবেন না। তিনি এটি নিয়ে আসেননি।
ব্যবহারকারী 9282

84
@ মামামা - সম্ভবত, তবে এটি তার কাছে দায়ী। হেনরি ফোর্ড গাড়ি আবিষ্কার করেনি, রাইট ব্রোস বিমানটি আবিষ্কার করেনি, এবং পৃথিবী সূর্যের চারদিকে আবর্তিত হয়েছিল তা নির্ধারণকারী গ্যালেলিও প্রথম নন ... বিশ্ব চুরির উদ্ভাবন নিয়ে গঠিত (এবং ভালবাসা).
রবার্ট ফ্রেজার

4
আপনি ((1<<(n&15))|65004) != 0তিনটি পৃথক চেকের পরিবর্তে এর মতো কিছু ব্যবহার করে 'কুইকফেইলে' একটি সামান্য গতি বৃদ্ধি পেতে পারেন।
নবাব

উত্তর:


735

আমি এমন একটি পদ্ধতি খুঁজে পেয়েছি যা কমপক্ষে আমার সিপিইউ (x86) এবং প্রোগ্রামিং ল্যাঙ্গুয়েজ (সি / সি ++) এর সাথে আপনার 6 বিট + কারম্যাক + স্কয়ার্ট কোডের চেয়ে 35% দ্রুত কাজ করে। আপনার ফলাফলগুলি পৃথক হতে পারে, বিশেষত কারণ জাভা ফ্যাক্টরটি কীভাবে কার্যকর হবে তা আমি জানি না।

আমার দৃষ্টিভঙ্গি তিনগুণ:

  1. প্রথমে সুস্পষ্ট উত্তরগুলি ফিল্টার করুন। এটি নেতিবাচক সংখ্যা অন্তর্ভুক্ত এবং শেষ 4 বিট খুঁজছেন। (আমি খুঁজে পেয়েছি শেষ ছয়টি দেখে কোনও লাভ হয়নি।) আমি 0 এর জন্য হ্যাঁ উত্তরও দিয়েছি (নীচের কোডটি পড়ার ক্ষেত্রে, আমার ইনপুটটি নোট করুন is int64 x)
    if( x < 0 || (x&2) || ((x & 7) == 5) || ((x & 11) == 8) )
        return false;
    if( x == 0 )
        return true;
  2. এরপরে, এটি 255 = 3 * 5 * 17 বর্গাকার মডুলোর কিনা তা পরীক্ষা করে দেখুন Because কারণ এটি তিনটি স্বতন্ত্র প্রাইমের একটি পণ্য, প্রায় 258 টির প্রায় 258 অংশের বর্গাকার হয় are তবে, আমার অভিজ্ঞতায়, মডুলো অপারেটরকে (%) কল করা তার সুবিধার চেয়ে বেশি খরচ করে, তাই আমি অবশিষ্টাংশের গণনা করতে 255 = 2 ^ 8-1 জড়িত বিট কৌশলগুলি ব্যবহার করি। (আরও ভাল বা আরও খারাপের জন্য, আমি কোনও শব্দ থেকে পৃথক বাইটগুলি পড়ার কৌশলটি ব্যবহার করছি না, কেবল বিটওয়াইস এবং শিফট।)
    int64 y = x;
    y = (y & 4294967295LL) + (y >> 32); 
    y = (y & 65535) + (y >> 16);
    y = (y & 255) + ((y >> 8) & 255) + (y >> 16);
    // At this point, y is between 0 and 511.  More code can reduce it farther.
    বাস্তবে অবশিষ্টাংশটি একটি বর্গক্ষেত্র কিনা তা যাচাই করার জন্য, আমি উত্তরটি একটি পূর্বনির্ধারিত সারণিতে সন্ধান করি।
    if( bad255[y] )
        return false;
    // However, I just use a table of size 512
  3. অবশেষে, হেনসেলের লেমার মতো একটি পদ্ধতি ব্যবহার করে বর্গমূলকে গণনা করার চেষ্টা করুন । (আমি এটি সরাসরি প্রযোজ্য বলে মনে করি না তবে এটি কিছু সংশোধন করে কাজ করে)) এটি করার আগে, আমি বাইনারি অনুসন্ধানের সাথে 2 এর সমস্ত ক্ষমতা বিভক্ত করি:
    if((x & 4294967295LL) == 0)
        x >>= 32;
    if((x & 65535) == 0)
        x >>= 16;
    if((x & 255) == 0)
        x >>= 8;
    if((x & 15) == 0)
        x >>= 4;
    if((x & 3) == 0)
        x >>= 2;
    এই মুহুর্তে, আমাদের সংখ্যাটি একটি বর্গক্ষেত্র হওয়ার জন্য, এটি 1 মড 8 হতে হবে।
    if((x & 7) != 1)
        return false;
    হেনসেলের লেমার মূল কাঠামোটি নিম্নরূপ। (দ্রষ্টব্য: অনির্ধারিত কোড; এটি যদি কাজ না করে তবে t = 2 বা 8 চেষ্টা করুন)
    int64 t = 4, r = 1;
    t <<= 1; r += ((x - r * r) & t) >> 1;
    t <<= 1; r += ((x - r * r) & t) >> 1;
    t <<= 1; r += ((x - r * r) & t) >> 1;
    // Repeat until t is 2^33 or so.  Use a loop if you want.
    ধারণাটি হ'ল প্রতিটি পুনরাবৃত্তির সময় আপনি আর এর সাথে একটি বিট যোগ করেন, এক্স এর "বর্তমান" বর্গমূল; প্রতিটি বর্গমূল হ'ল মডিউল 2 এর বৃহত্তর এবং বৃহত্তর শক্তি, যথা t / 2। শেষে, আর এবং টি / 2-আর এক্স মডুলো টি / 2 এর বর্গমূল হবে। (দ্রষ্টব্য যে r যদি x এর বর্গমূল হয় তবে এর পরিমাণও সঠিক r এটি এমনকি মডুলো সংখ্যাও সত্য, তবে সাবধান থাকুন, কিছু সংখ্যক মডুলও 2 টিরও বেশি বর্গমূল হতে পারে; উল্লেখযোগ্যভাবে এর মধ্যে 2 এর শক্তিও রয়েছে। ) যেহেতু আমাদের আসল বর্গমূল 2। 32 এরও কম, আমরা ঠিক তখনই পরীক্ষা করতে পারি যে r বা t / 2-r রিয়েল বর্গমূল কিনা। আমার আসল কোডে আমি নিম্নলিখিত সংশোধিত লুপটি ব্যবহার করছি:
    int64 r, t, z;
    r = start[(x >> 3) & 1023];
    do {
        z = x - r * r;
        if( z == 0 )
            return true;
        if( z < 0 )
            return false;
        t = z & (-z);
        r += (z & t) >> 1;
        if( r > (t >> 1) )
            r = t - r;
    } while( t <= (1LL << 33) );
    এখানে স্পিডআপটি তিনটি উপায়ে পাওয়া যায়: প্রাক্পম্পিউটেড স্টার্ট মান (লুপের ite 10 পুনরাবৃত্তির সমতুল্য), লুপের প্রারম্ভিক প্রস্থান এবং কিছু টি মান বাদ দেওয়া। শেষ অংশের জন্য, আমি z = r - x * xকিছুটা কৌতুক সহ 2 বিভাজক জেডের বৃহত্তম শক্তি হতে চেষ্টা করেছি এবং সেট করেছি। এটি আমাকে টি মানগুলি এড়িয়ে যাওয়ার অনুমতি দেয় যা যে কোনওভাবে আর এর মানকে প্রভাবিত করে না। আমার ক্ষেত্রে পূর্বনির্ধারিত প্রারম্ভিক মানটি "ক্ষুদ্রতম ধনাত্মক" বর্গমূলের মডুলো 8192 এনেছে।

এমনকি যদি এই কোডটি আপনার পক্ষে দ্রুত কাজ না করে তবে আমি আশা করি আপনি এতে থাকা কিছু ধারণাগুলি উপভোগ করবেন। সম্পূর্ণ, পরীক্ষিত কোড অনুসরণ করে পূর্বনির্ধারিত সারণীগুলি সহ।

typedef signed long long int int64;

int start[1024] =
{1,3,1769,5,1937,1741,7,1451,479,157,9,91,945,659,1817,11,
1983,707,1321,1211,1071,13,1479,405,415,1501,1609,741,15,339,1703,203,
129,1411,873,1669,17,1715,1145,1835,351,1251,887,1573,975,19,1127,395,
1855,1981,425,453,1105,653,327,21,287,93,713,1691,1935,301,551,587,
257,1277,23,763,1903,1075,1799,1877,223,1437,1783,859,1201,621,25,779,
1727,573,471,1979,815,1293,825,363,159,1315,183,27,241,941,601,971,
385,131,919,901,273,435,647,1493,95,29,1417,805,719,1261,1177,1163,
1599,835,1367,315,1361,1933,1977,747,31,1373,1079,1637,1679,1581,1753,1355,
513,1539,1815,1531,1647,205,505,1109,33,1379,521,1627,1457,1901,1767,1547,
1471,1853,1833,1349,559,1523,967,1131,97,35,1975,795,497,1875,1191,1739,
641,1149,1385,133,529,845,1657,725,161,1309,375,37,463,1555,615,1931,
1343,445,937,1083,1617,883,185,1515,225,1443,1225,869,1423,1235,39,1973,
769,259,489,1797,1391,1485,1287,341,289,99,1271,1701,1713,915,537,1781,
1215,963,41,581,303,243,1337,1899,353,1245,329,1563,753,595,1113,1589,
897,1667,407,635,785,1971,135,43,417,1507,1929,731,207,275,1689,1397,
1087,1725,855,1851,1873,397,1607,1813,481,163,567,101,1167,45,1831,1205,
1025,1021,1303,1029,1135,1331,1017,427,545,1181,1033,933,1969,365,1255,1013,
959,317,1751,187,47,1037,455,1429,609,1571,1463,1765,1009,685,679,821,
1153,387,1897,1403,1041,691,1927,811,673,227,137,1499,49,1005,103,629,
831,1091,1449,1477,1967,1677,697,1045,737,1117,1737,667,911,1325,473,437,
1281,1795,1001,261,879,51,775,1195,801,1635,759,165,1871,1645,1049,245,
703,1597,553,955,209,1779,1849,661,865,291,841,997,1265,1965,1625,53,
1409,893,105,1925,1297,589,377,1579,929,1053,1655,1829,305,1811,1895,139,
575,189,343,709,1711,1139,1095,277,993,1699,55,1435,655,1491,1319,331,
1537,515,791,507,623,1229,1529,1963,1057,355,1545,603,1615,1171,743,523,
447,1219,1239,1723,465,499,57,107,1121,989,951,229,1521,851,167,715,
1665,1923,1687,1157,1553,1869,1415,1749,1185,1763,649,1061,561,531,409,907,
319,1469,1961,59,1455,141,1209,491,1249,419,1847,1893,399,211,985,1099,
1793,765,1513,1275,367,1587,263,1365,1313,925,247,1371,1359,109,1561,1291,
191,61,1065,1605,721,781,1735,875,1377,1827,1353,539,1777,429,1959,1483,
1921,643,617,389,1809,947,889,981,1441,483,1143,293,817,749,1383,1675,
63,1347,169,827,1199,1421,583,1259,1505,861,457,1125,143,1069,807,1867,
2047,2045,279,2043,111,307,2041,597,1569,1891,2039,1957,1103,1389,231,2037,
65,1341,727,837,977,2035,569,1643,1633,547,439,1307,2033,1709,345,1845,
1919,637,1175,379,2031,333,903,213,1697,797,1161,475,1073,2029,921,1653,
193,67,1623,1595,943,1395,1721,2027,1761,1955,1335,357,113,1747,1497,1461,
1791,771,2025,1285,145,973,249,171,1825,611,265,1189,847,1427,2023,1269,
321,1475,1577,69,1233,755,1223,1685,1889,733,1865,2021,1807,1107,1447,1077,
1663,1917,1129,1147,1775,1613,1401,555,1953,2019,631,1243,1329,787,871,885,
449,1213,681,1733,687,115,71,1301,2017,675,969,411,369,467,295,693,
1535,509,233,517,401,1843,1543,939,2015,669,1527,421,591,147,281,501,
577,195,215,699,1489,525,1081,917,1951,2013,73,1253,1551,173,857,309,
1407,899,663,1915,1519,1203,391,1323,1887,739,1673,2011,1585,493,1433,117,
705,1603,1111,965,431,1165,1863,533,1823,605,823,1179,625,813,2009,75,
1279,1789,1559,251,657,563,761,1707,1759,1949,777,347,335,1133,1511,267,
833,1085,2007,1467,1745,1805,711,149,1695,803,1719,485,1295,1453,935,459,
1151,381,1641,1413,1263,77,1913,2005,1631,541,119,1317,1841,1773,359,651,
961,323,1193,197,175,1651,441,235,1567,1885,1481,1947,881,2003,217,843,
1023,1027,745,1019,913,717,1031,1621,1503,867,1015,1115,79,1683,793,1035,
1089,1731,297,1861,2001,1011,1593,619,1439,477,585,283,1039,1363,1369,1227,
895,1661,151,645,1007,1357,121,1237,1375,1821,1911,549,1999,1043,1945,1419,
1217,957,599,571,81,371,1351,1003,1311,931,311,1381,1137,723,1575,1611,
767,253,1047,1787,1169,1997,1273,853,1247,413,1289,1883,177,403,999,1803,
1345,451,1495,1093,1839,269,199,1387,1183,1757,1207,1051,783,83,423,1995,
639,1155,1943,123,751,1459,1671,469,1119,995,393,219,1743,237,153,1909,
1473,1859,1705,1339,337,909,953,1771,1055,349,1993,613,1393,557,729,1717,
511,1533,1257,1541,1425,819,519,85,991,1693,503,1445,433,877,1305,1525,
1601,829,809,325,1583,1549,1991,1941,927,1059,1097,1819,527,1197,1881,1333,
383,125,361,891,495,179,633,299,863,285,1399,987,1487,1517,1639,1141,
1729,579,87,1989,593,1907,839,1557,799,1629,201,155,1649,1837,1063,949,
255,1283,535,773,1681,461,1785,683,735,1123,1801,677,689,1939,487,757,
1857,1987,983,443,1327,1267,313,1173,671,221,695,1509,271,1619,89,565,
127,1405,1431,1659,239,1101,1159,1067,607,1565,905,1755,1231,1299,665,373,
1985,701,1879,1221,849,627,1465,789,543,1187,1591,923,1905,979,1241,181};

bool bad255[512] =
{0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,0,0,1,1,0,1,0,1,1,1,0,1,1,1,1,0,1,
 1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,0,1,1,1,
 0,1,0,1,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,
 1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,
 1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,
 1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,
 1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,
 1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
 0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,0,0,1,1,0,1,0,1,1,1,0,1,1,1,1,0,1,
 1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,0,1,1,1,
 0,1,0,1,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,
 1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,
 1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,
 1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,
 1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,
 1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
 0,0};

inline bool square( int64 x ) {
    // Quickfail
    if( x < 0 || (x&2) || ((x & 7) == 5) || ((x & 11) == 8) )
        return false;
    if( x == 0 )
        return true;

    // Check mod 255 = 3 * 5 * 17, for fun
    int64 y = x;
    y = (y & 4294967295LL) + (y >> 32);
    y = (y & 65535) + (y >> 16);
    y = (y & 255) + ((y >> 8) & 255) + (y >> 16);
    if( bad255[y] )
        return false;

    // Divide out powers of 4 using binary search
    if((x & 4294967295LL) == 0)
        x >>= 32;
    if((x & 65535) == 0)
        x >>= 16;
    if((x & 255) == 0)
        x >>= 8;
    if((x & 15) == 0)
        x >>= 4;
    if((x & 3) == 0)
        x >>= 2;

    if((x & 7) != 1)
        return false;

    // Compute sqrt using something like Hensel's lemma
    int64 r, t, z;
    r = start[(x >> 3) & 1023];
    do {
        z = x - r * r;
        if( z == 0 )
            return true;
        if( z < 0 )
            return false;
        t = z & (-z);
        r += (z & t) >> 1;
        if( r > (t  >> 1) )
            r = t - r;
    } while( t <= (1LL << 33) );

    return false;
}

5
কি দারুন! আমি এটি জাভাতে রূপান্তরিত করার চেষ্টা করব এবং তুলনা করার পাশাপাশি ফলাফলগুলিতে নির্ভুলতা যাচাই করব। আমি যা জানি তা আপনাকে জানাব।
কিপ

79
বাহ, এটি সুন্দর। আমি হেনসেলকে উত্তোলনের আগে দেখতে পেলাম (বহুবর্ষগুলির শিকড় গণনা করে) তবে আমি বুঝতেও পারি নি যে সংখ্যার বর্গমূলকে গণনার জন্য লেমাকে সাবধানে হ্রাস করা যেতে পারে; এটি ... উত্থাপন :)
শ্রীভাতসার

3
@ নাইটক্র্যাকার এটি করে না 9 < 0 => false, 9&2 => 0, 9&7 == 5 => false, 9&11 == 8 => false
প্রিমো

53
মার্টিনাস নীচে একটি 2x দ্রুত সমাধান (এবং আরও সংক্ষিপ্ত) পোস্ট করেছেন, খানিক পরে, এটি খুব বেশি ভালবাসা পাচ্ছে বলে মনে হয় না।
জেসন সি

3
দেখে মনে হচ্ছে স্পষ্ট স্কোয়ারগুলি ফিল্টার করে বিভিন্ন সমাধানগুলিতে প্রচুর গতির সুবিধা পাওয়া যায়। মার্টিনাসের সমাধানের মাধ্যমে ফিল্টার আউট করার পরিস্থিতিটি কি কেউ কোনও অন্তর্নির্মিত ফাংশন হিসাবে ঠিক তখন স্কয়ার্ট ফাংশনটি ব্যবহার করে?
ব্যবহারকারী 1914292

376

আমি পার্টিতে বেশ দেরি করেছি, তবে আমি আরও ভাল উত্তর দেওয়ার আশাবাদী; আরও ছোট এবং (আমার মানদণ্ডটি সঠিক বলে ধরে নিচ্ছি ) আরও দ্রুত গতিতে

long goodMask; // 0xC840C04048404040 computed below
{
    for (int i=0; i<64; ++i) goodMask |= Long.MIN_VALUE >>> (i*i);
}

public boolean isSquare(long x) {
    // This tests if the 6 least significant bits are right.
    // Moving the to be tested bit to the highest position saves us masking.
    if (goodMask << x >= 0) return false;
    final int numberOfTrailingZeros = Long.numberOfTrailingZeros(x);
    // Each square ends with an even number of zeros.
    if ((numberOfTrailingZeros & 1) != 0) return false;
    x >>= numberOfTrailingZeros;
    // Now x is either 0 or odd.
    // In binary each odd square ends with 001.
    // Postpone the sign test until now; handle zero in the branch.
    if ((x&7) != 1 | x <= 0) return x == 0;
    // Do it in the classical way.
    // The correctness is not trivial as the conversion from long to double is lossy!
    final long tst = (long) Math.sqrt(x);
    return tst * tst == x;
}

প্রথম পরীক্ষাটি বেশিরভাগ অ-স্কোয়ারকে দ্রুত ধরা দেয়। এটি একটি দীর্ঘ in৪ টি আইটেমের টেবিল ব্যবহার করে, তাই কোনও অ্যারে অ্যাক্সেস ব্যয় নেই (দিকনির্দেশ এবং সীমা পরীক্ষাগুলি)। অভিন্ন এলোমেলো জন্য longএখানে 81.25% শেষ হওয়ার সম্ভাবনা আছে।

দ্বিতীয় পরীক্ষায় সমস্ত সংখ্যার জোড় সংখ্যক সংখ্যার গুণককে নির্ধারণ করা হয়। পদ্ধতিটি Long.numberOfTrailingZerosখুব দ্রুত গতিযুক্ত হওয়ায় এটি জেআইডি-এডকে একক আই 86৮ নির্দেশিকায় রূপান্তরিত করে।

পেছনের শূন্যগুলি বাদ দেওয়ার পরে, তৃতীয় পরীক্ষায় বাইনারিতে 011, 101 বা 111 সমাপ্ত নম্বরগুলি পরিচালনা করে, যা কোনও নিখুঁত স্কোয়ার নয়। এটি নেতিবাচক সংখ্যাগুলি সম্পর্কেও যত্নশীল এবং 0 টি পরিচালনা করে।

চূড়ান্ত পরীক্ষা doubleপাটিগণিতের কাছে ফিরে আসে । হিসাবে doubleমাত্র 53 বিট অংশক থেকে রূপান্তর হয়েছে longথেকে doubleবড় মানের জন্য rounding অন্তর্ভুক্ত। তবুও, পরীক্ষাটি সঠিক ( প্রমাণটি ভুল না হলে )।

Mod255 ধারণাটি অন্তর্ভুক্ত করার চেষ্টা করা সফল হয়নি।


3
শিফ্ট মানটির সেই অন্তর্নিহিত মুখোশটি কিছুটা ... খারাপ। জাভা স্পেসে কেন আপনার কোনও ধারণা আছে?
dfeuer

5
@ ডিফিউয়ার আমার ধারণা, এর দুটি কারণ রয়েছে: ১. আরও বেশি করে স্থানান্তর করা কোনও অর্থহীন নয়। ২. এটি এইচডাব্লুয়ের মতো কাজ করে এবং বিটওয়াইজ অপারেশন ব্যবহার করা যে কেউ পারফরম্যান্সে আগ্রহী তাই অন্য যে কোনও কিছু করা ভুল হবে। -goodMask পরীক্ষা এটা আছে, কিন্তু এটা এটা আছে সামনে ডান শিফ্ট। সুতরাং আপনাকে এটির পুনরাবৃত্তি করতে হবে, তবে এই উপায়টি সহজ এবং আফাইক সামান্য কিছুটা দ্রুত এবং সমানভাবে ভাল।
মার্টিনাস

2
@dfeuer মানদণ্ডের জন্য এটি ASAP উত্তর দেওয়া জরুরী, এবং শূন্যের গণনা নিজেই কোনও উত্তর দেয় না; এটি কেবল একটি প্রস্তুতিমূলক পদক্ষেপ। i86 / amd64 এটি করুন। মোবাইলগুলিতে ছোট সিপিইউ সম্পর্কে কোনও ধারণা নেই, তবে সবচেয়ে খারাপ দিক থেকে জাভাকে তাদের জন্য একটি AND নির্দেশিকা তৈরি করতে হবে, যা অবশ্যই অন্যান্য উপায়ের চেয়ে সহজ।
মার্টিনাস

2
@Sebastian একজন সম্ভবত ভাল পরীক্ষা: if ((x & (7 | Integer.MIN_VALUE)) != 1) return x == 0;
মাআর্টিনাস

4
"যেহেতু ডাবলটিতে কেবল 56 বিট ম্যান্টিসা রয়েছে" -> আমি বলব এটির সম্ভবত 53 টি বিট রয়েছেএছাড়াও
chux - মনিকাকে পুনরায় ইনস্টল করুন

132

আপনাকে কিছু বেঞ্চমার্কিং করতে হবে। সেরা অ্যালগরিদম আপনার ইনপুট বিতরণের উপর নির্ভর করবে।

আপনার অ্যালগরিদম প্রায় অনুকূল হতে পারে, তবে আপনি আপনার বর্গক্ষেত্রের রুটিনটি কল করার আগে কিছু সম্ভাবনা বাতিল করার জন্য দ্রুত চেক করতে চাইতে পারেন। উদাহরণস্বরূপ, কিছুটা বুদ্ধিমান করে "এবং" হেক্সে আপনার সংখ্যার শেষ সংখ্যাটি দেখুন। নিখুঁত স্কোয়ারগুলি কেবলমাত্র বেস, ১, ৪, বা ৯ এর মধ্যে শেষ হতে পারে, সুতরাং আপনার ইনপুটগুলির %৫% এর জন্য (তারা সমানভাবে বিতরণ করা হয়েছে তা ধরে নিই) আপনি কিছু খুব দ্রুত বিট বার করার বিনিময়ে বর্গমূলের কলটি এড়াতে পারবেন।

কিপ হেক্স ট্রিকটি প্রয়োগ করে নিম্নলিখিত কোডটি বেঞ্চমার্ক করেছে। ১,০০,০০,০০,০০০ এর মাধ্যমে সংখ্যার পরীক্ষা করার সময়, এই কোডটি মূলটির চেয়ে দ্বিগুণ দ্রুত চলে।

public final static boolean isPerfectSquare(long n)
{
    if (n < 0)
        return false;

    switch((int)(n & 0xF))
    {
    case 0: case 1: case 4: case 9:
        long tst = (long)Math.sqrt(n);
        return tst*tst == n;

    default:
        return false;
    }
}

আমি যখন সি ++ তে সাদৃশ্য কোডটি পরীক্ষা করেছি তখন এটি আসলটির চেয়ে আসলে ধীরে চলেছে ran যাইহোক, যখন আমি স্যুইচ বিবৃতিটি সরিয়ে ফেললাম, হেক্স ট্রিকটি আবারও দ্বিগুণ তত দ্রুত কোডটি তৈরি করে।

int isPerfectSquare(int n)
{
    int h = n & 0xF;  // h is the last hex "digit"
    if (h > 9)
        return 0;
    // Use lazy evaluation to jump out of the if statement as soon as possible
    if (h != 2 && h != 3 && h != 5 && h != 6 && h != 7 && h != 8)
    {
        int t = (int) floor( sqrt((double) n) + 0.5 );
        return t*t == n;
    }
    return 0;
}

স্যুইচ স্টেটমেন্টটি বাদ দেওয়ার সি # কোডে খুব কম প্রভাব পড়ে।


এটি বেশ চালাক ... এর কথা ভাবেননি
ওয়ারেন

পিছনের বিট সম্পর্কে দুর্দান্ত পয়েন্ট। আমি এখানে অন্য কয়েকটি মন্তব্যের সাথে সেই পরীক্ষাটি একত্রিত করার চেষ্টা করব।
পিটারআলেন ওয়েলব

3
চমত্কার সমাধান। ভাবছেন কীভাবে আপনি এটি নিয়ে এসেছেন? একটি মোটামুটি প্রতিষ্ঠিত নীতি বা ঠিক এমন কিছু যা আপনি বের করেছেন? : ডি
জিল শাহ 7'11

3
@ লার্শ ০.৫ যোগ করার দরকার নেই, প্রমাণটির লিঙ্কের জন্য আমার সমাধান দেখুন।
মার্টিনাস

2
@ জেরিওয়েল এটি সংকলক এবং কেসগুলির মানগুলির উপর নির্ভর করে। নিখুঁত সংকলকটিতে, একটি স্যুইচ সর্বদা কমপক্ষে তত দ্রুত হয় - অন্যটি হিসাবে। তবে সংকলকগুলি নিখুঁত নয়, তাই জন চেষ্টা করার মতো চেষ্টা করে দেখা ভাল।
ফিশিনিয়ার

52

আমি সংখ্যা বিশ্লেষণ কোর্সে কাটিয়েছি এমন ভয়াবহ সময় সম্পর্কে আমি ভাবছিলাম।

এবং তারপরে আমার মনে আছে, ভূমিকম্প উত্স কোড থেকে 'নেট'র চারপাশে এই ফাংশনটি ঘুরছিল:

float Q_rsqrt( float number )
{
  long i;
  float x2, y;
  const float threehalfs = 1.5F;

  x2 = number * 0.5F;
  y  = number;
  i  = * ( long * ) &y;  // evil floating point bit level hacking
  i  = 0x5f3759df - ( i >> 1 ); // wtf?
  y  = * ( float * ) &i;
  y  = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
  // y  = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed

  #ifndef Q3_VM
  #ifdef __linux__
    assert( !isnan(y) ); // bk010122 - FPE?
  #endif
  #endif
  return y;
}

যা নিউটনের আনুমানিক ফাংশন (সঠিক নামটি মনে করতে পারে না) ব্যবহার করে মূলত একটি বর্গমূলের গণনা করে।

এটি ব্যবহারযোগ্য এবং এটি আরও দ্রুততর হওয়া উচিত, এটি এক অসাধারণ আইডি সফ্টওয়্যার এর গেম থেকে!

এটি সি ++ তে লেখা হয়েছে তবে জাভাতে একই কৌশলটি পুনরায় ব্যবহার করা আপনার পক্ষে খুব কঠিন হওয়া উচিত নয়:

আমি এটি মূলত: http://www.codemaestro.com/reviews/9 এ পেয়েছি

নিউটনের পদ্ধতিটি উইকিপিডিয়াতে ব্যাখ্যা করা হয়েছে: http://en.wikedia.org/wiki/Newton%27s_ স্মারক

এটি কীভাবে কাজ করে তার আরও ব্যাখ্যার জন্য আপনি লিঙ্কটি অনুসরণ করতে পারেন তবে আপনি যদি খুব বেশি চিন্তা করেন না তবে ব্লগটি পড়া এবং সংখ্যার বিশ্লেষণের কোর্সটি গ্রহণ করা থেকে আমি প্রায় এটিই মনে করি:

  • * (long*) &yমূলত একটি ফাস্ট ধর্মান্তরিত টু দীর্ঘ ফাংশন তাই পূর্ণসংখ্যা অপারেশন কাঁচা বাইট উপর প্রয়োগ করা যেতে পারে।
  • 0x5f3759df - (i >> 1);লাইন পড়তা ফাংশন জন্য একটি প্রি-গণনা করা বীজ মান।
  • * (float*) &iফ্লোটিং পয়েন্ট মান ফিরে পরিবর্তন করে।
  • y = y * ( threehalfs - ( x2 * y * y ) )লাইন bascially আবার ফাংশন উপর মান iterates।

আনুমানিক ফাংশন ফলাফলের উপরে ফাংশনটিকে যত বেশি পুনরাবৃত্তি করবে আরও সুনির্দিষ্ট মান দেয়। কোকের ক্ষেত্রে, একটি পুনরাবৃত্তি "যথেষ্ট ভাল", তবে এটি যদি আপনার না হয় ... তবে আপনি যতটা পুনরুক্তি প্রয়োজন তেমন যোগ করতে পারেন।

এটি দ্রুত হওয়া উচিত কারণ এটি সরল বর্গাকারে বিভাজনমূলক ক্রিয়াকলাপগুলি হ্রাস করে সাধারণ ভাগে 2 (আসলে একটি * 0.5Fগুণিত অপারেশন) করে এবং এর পরিবর্তে কয়েকটি নির্দিষ্ট সংখ্যার গুণের ক্রিয়াকলাপ দিয়ে এটি প্রতিস্থাপন করে।


9
এটি লক্ষ করা উচিত যে এটি 1 / স্কয়ার্ট (নম্বর) প্রদান করে, স্কয়ার্ট (নম্বর) নয়। আমি কিছু পরীক্ষা করেছি এবং এটি এন = 410881 থেকে ব্যর্থ হয়েছে: জন কারম্যাক ম্যাজিক সূত্রটি আসল বর্গমূল যখন 641 হয় তখন 2৪২.০১০৪ ফিরে আসে।
কিপ

11
আপনি ক্রিস লোমোন্টস পেপারটি দ্রুত বিপরীতমুখী স্কোয়ার শিকড়গুলির দিকে দেখতে পেলেন : lomont.org/Math/Papers/2003/Ivvqrt.pdf এটি এখানে একই কৌশল ব্যবহার করে তবে ভিন্ন যাদু সংখ্যার সাথে। কাগজটি ব্যাখ্যা করে যে কেন যাদু নম্বরটি বেছে নেওয়া হয়েছিল।

4
এছাড়াও, 3d.com / কনটেন্ট / আর্টিকেলস 8 এবং এর বাইরে3 d.com/content/articles/15 এই পদ্ধতির উত্স সম্পর্কে কিছুটা আলোকপাত করেছে। এটি প্রায়শই জন কারম্যাককে দায়ী করা হয় তবে মনে হয় মূল কোডটি (সম্ভবত) গ্যারি টারোল্লি, গ্রেগ ওয়ালশ এবং সম্ভবত অন্যরা লিখেছিলেন।

3
এছাড়াও আপনি জাভাতে টাইপপান ভাসমান এবং ইনটস করতে পারবেন না।
অ্যান্টিমনি

10
@ অ্যান্টিমনি কে বলে? জাভা ১.০.২ থেকে ফ্লোটটোইন্টবিটস এবং ইন্টটোফ্লোটবিটস প্রায় রয়েছে।
কর্সিকা ২

38

এটি দ্রুত, বা এমনকি সঠিক হবে কিনা তা আমি নিশ্চিত নই তবে আপনি বর্গমূলকে দ্রুত সমাধান করতে জন কারম্যাকের যাদুকরী স্কোয়ার রুট , অ্যালগরিদম ব্যবহার করতে পারেন । আপনি সম্ভবত এটি সম্ভব 32 বিট পূর্ণসংখ্যার জন্য সহজেই পরীক্ষা করে দেখতে পারেন এবং সত্যই সঠিক ফলাফল পেয়েছেন তা বৈধতা হিসাবে এটি কেবলমাত্র একটি আপক্সিমেশন। যাইহোক, এখন আমি এটি সম্পর্কে চিন্তা করি, ডাবল ব্যবহার করাও প্রায় সমান, সুতরাং কীভাবে এটি কার্যকর হবে তা আমি নিশ্চিত নই।


10
আমি বিশ্বাস করি কারম্যাকের কৌশলটি আজকাল মোটামুটি অর্থহীন। অন্তর্নির্মিত স্কয়ার্ট নির্দেশটি আগের তুলনায় অনেক দ্রুত, সুতরাং আপনি যদি নিয়মিত স্কোয়ার রুটটি পরীক্ষা করে থাকেন এবং ফলাফলটি যদি কোন int হয় তবে তা পরীক্ষা করে নেওয়া ভাল। সর্বদা হিসাবে, এটি মানদণ্ড।
jalf

4
এই বিরতি n = 410881 থেকে শুরু হবে, জন কারম্যাক ম্যাজিক সূত্রটি 642.00104 প্রদান করবে, যখন আসল বর্গমূল হবে 641.
কিপ

11
আমি সম্প্রতি একটি জাভা গেমটিতে কারম্যাকের কৌশলটি ব্যবহার করেছি এবং এটি প্রায় কার্যকর ছিল, প্রায় ৪০% গতিবেগ দেয়, তাই এটি এখনও কার্যকর, অন্তত জাভাতে।
ফিনওয়ান

3
সামগ্রিক ফ্রেমের হারে @ রবার্ট ফ্রেজার হ্যাঁ + 40%। গেমটিতে একটি কণা পদার্থবিজ্ঞান সিস্টেম ছিল যা স্কোয়ার রুট ফাংশন এবং রাউন্ড টু নিকটতম-পূর্ণসংখ্যা ফাংশন দ্বারা প্রভাবিত প্রায় সমস্ত উপলব্ধ সিপিইউ চক্র গ্রহণ করেছিল (যা আমি একই ধরণের বিট টুইডলিং হ্যাক ব্যবহার করেও অনুকূলিত করেছিলাম))
ফাইন

5
লিঙ্কটি নষ্ট হয়ে গেছে।
পিক্সার

36

"ডান" স্কোয়ার রুটটি সন্ধান করার জন্য আপনি যদি বাইনারি চপ করেন তবে আপনি যে মানটি পেয়েছেন তা যথেষ্ট পরিমাণে বলার অপেক্ষা রাখে আপনি খুব সহজেই সনাক্ত করতে পারেন:

(n+1)^2 = n^2 + 2n + 1
(n-1)^2 = n^2 - 2n + 1

সুতরাং গণনা করা n^2, বিকল্পগুলি হ'ল:

  • n^2 = target: সম্পন্ন, সত্য ফিরে
  • n^2 + 2n + 1 > target > n^2 : আপনি কাছাকাছি, কিন্তু এটি নিখুঁত নয়: মিথ্যা প্রত্যাবর্তন করুন
  • n^2 - 2n + 1 < target < n^2 : ditto
  • target < n^2 - 2n + 1 : একটি নিম্নে বাইনারি চপ n
  • target > n^2 + 2n + 1 : উচ্চতর উপর বাইনারি চপ n

(দুঃখিত, এটি nআপনার বর্তমান অনুমান হিসাবে ব্যবহার করে , এবংtarget পরামিতি হিসাবে ব্যবহার করে the বিভ্রান্তির জন্য ক্ষমা প্রার্থনা করুন!)

আমি জানি না এটি দ্রুত হবে কি না, তবে এটি চেষ্টা করার মতো।

সম্পাদনা: বাইনারি চপটি পুরো সংখ্যার পূর্ণ পরিসীমা গ্রহণ করতে হবে না (2^x)^2 = 2^(2x), সুতরাং, একবার আপনি আপনার টার্গেটের শীর্ষ সেট বিটটি খুঁজে পেয়েছেন (যা কিছুটা বিড়াল দেওয়ার কৌশল দিয়ে করা যেতে পারে; আমি ঠিক কীভাবে ভুলে গেছি) আপনি দ্রুত সম্ভাব্য উত্তরগুলির একটি পরিসীমা পেতে পারেন। মনে মনে, একটি নিষ্পাপ বাইনারি চপ এখনও কেবল 31 বা 32 পুনরাবৃত্তির অবধি নিতে চলেছে।


আমার অর্থ এই ধরণের পদ্ধতির উপর রয়েছে। স্কয়ার্ট () কল করা থেকে বিরত থাকুন কারণ এটি একটি পূর্ণ বর্গাকার মূল গণনা করছে এবং আপনার কেবল প্রথম কয়েকটি অঙ্কের প্রয়োজন।
পিটারআলেন ওয়েলব

3
অন্যদিকে, যদি কোনও উত্সর্গীকৃত এফপি ইউনিটে ভাসমান পয়েন্টটি করা হচ্ছে, তবে এটি সমস্ত ধরণের মজাদার কৌশল ব্যবহার করতে পারে। আমি কোনও মানদণ্ড ছাড়াই এটিতে বাজি ধরতে চাই না :) (আমি আজ রাতে এটি চেষ্টা করতে পারি যদিও সি # তে, কেবল দেখতে ...)
জন স্কিটি

8
হার্ডওয়্যার স্কয়ারগুলি আজকাল বেশ দ্রুত।
অ্যাডাম রোজেনফিল্ড

24

আমি এই থ্রেডে বেশ কয়েকটি অ্যালগরিদমের নিজস্ব বিশ্লেষণ চালিয়েছি এবং কিছু নতুন ফলাফল নিয়ে এসেছি। আপনি এই উত্তরের সম্পাদনার ইতিহাসে সেই পুরানো ফলাফলগুলি দেখতে পাচ্ছেন, তবে সেগুলি সঠিক নয়, কারণ আমি ভুল করেছিলাম এবং বেশিরভাগ অ্যালগোরিদম যা খুব কাছে নেই তা বিশ্লেষণ করতে সময় নষ্ট করে। যাইহোক, বেশ কয়েকটি পৃথক উত্তর থেকে পাঠগুলি টানতে আমার কাছে এখন দুটি আলগোরিদিম রয়েছে যা এই থ্রেডের "বিজয়ী" কে নষ্ট করে। আমি সবার চেয়ে আলাদাভাবে করি এমন মূল জিনিসটি এখানে:

// This is faster because a number is divisible by 2^4 or more only 6% of the time
// and more than that a vanishingly small percentage.
while((x & 0x3) == 0) x >>= 2;
// This is effectively the same as the switch-case statement used in the original
// answer. 
if((x & 0x7) != 1) return false;

তবে, এই সরল রেখাটি, যা বেশিরভাগ সময় এক বা দুটি খুব দ্রুত নির্দেশাবলীর যোগ করে, এটিকে খুব সহজ করে switch-case বিবৃতিটি যদি বিবৃতিটিকে । যাইহোক, পরীক্ষিত সংখ্যার মধ্যে উল্লেখযোগ্য পাওয়ার-দু'টি কারণ থাকলে এটি রানটাইমে যুক্ত করতে পারে।

নীচে অ্যালগরিদম নীচে রয়েছে:

  • ইন্টারনেটের - কিপের পোস্ট করা উত্তর
  • Durron - বেস হিসাবে ওয়ান পাসের উত্তরটি ব্যবহার করে আমার পরিবর্তিত উত্তর
  • ডুররনটো - আমার কিছু সংশোধিত উত্তর এবং দ্বি-পাস উত্তর (@ জোহেনিহিগহিম দ্বারা) ব্যবহার করে using

নম্বরগুলি ব্যবহার করে তৈরি করা হয় তবে এটি একটি নমুনা রানটাইম Math.abs(java.util.Random.nextLong())

 0% Scenario{vm=java, trial=0, benchmark=Internet} 39673.40 ns; ?=378.78 ns @ 3 trials
33% Scenario{vm=java, trial=0, benchmark=Durron} 37785.75 ns; ?=478.86 ns @ 10 trials
67% Scenario{vm=java, trial=0, benchmark=DurronTwo} 35978.10 ns; ?=734.10 ns @ 10 trials

benchmark   us linear runtime
 Internet 39.7 ==============================
   Durron 37.8 ============================
DurronTwo 36.0 ===========================

vm: java
trial: 0

এবং এটি যদি প্রথম মিলিয়ন দীর্ঘায়িত হয় তবে একটি নমুনা রানটাইম এখানে রয়েছে:

 0% Scenario{vm=java, trial=0, benchmark=Internet} 2933380.84 ns; ?=56939.84 ns @ 10 trials
33% Scenario{vm=java, trial=0, benchmark=Durron} 2243266.81 ns; ?=50537.62 ns @ 10 trials
67% Scenario{vm=java, trial=0, benchmark=DurronTwo} 3159227.68 ns; ?=10766.22 ns @ 3 trials

benchmark   ms linear runtime
 Internet 2.93 ===========================
   Durron 2.24 =====================
DurronTwo 3.16 ==============================

vm: java
trial: 0

যেমন আপনি দেখতে পাচ্ছেন, DurronTwoবৃহত ইনপুটগুলির জন্য আরও ভাল করে তোলে কারণ এটি খুব ঘন ঘন যাদু কৌশল ব্যবহার করতে পারে তবে প্রথম অ্যালগরিদমের তুলনায় ক্লোবারড হয়ে যায় এবং Math.sqrtকারণ সংখ্যাগুলি এত কম। এদিকে, সরল Durronএকটি বিশাল বিজয়ী কারণ এটি প্রথম মিলিয়ন সংখ্যায় 4 টি বহুবার কখনও ভাগ করতে পারে না।

এখানে Durron:

public final static boolean isPerfectSquareDurron(long n) {
    if(n < 0) return false;
    if(n == 0) return true;

    long x = n;
    // This is faster because a number is divisible by 16 only 6% of the time
    // and more than that a vanishingly small percentage.
    while((x & 0x3) == 0) x >>= 2;
    // This is effectively the same as the switch-case statement used in the original
    // answer. 
    if((x & 0x7) == 1) {

        long sqrt;
        if(x < 410881L)
        {
            int i;
            float x2, y;

            x2 = x * 0.5F;
            y  = x;
            i  = Float.floatToRawIntBits(y);
            i  = 0x5f3759df - ( i >> 1 );
            y  = Float.intBitsToFloat(i);
            y  = y * ( 1.5F - ( x2 * y * y ) );

            sqrt = (long)(1.0F/y);
        } else {
            sqrt = (long) Math.sqrt(x);
        }
        return sqrt*sqrt == x;
    }
    return false;
}

এবং DurronTwo

public final static boolean isPerfectSquareDurronTwo(long n) {
    if(n < 0) return false;
    // Needed to prevent infinite loop
    if(n == 0) return true;

    long x = n;
    while((x & 0x3) == 0) x >>= 2;
    if((x & 0x7) == 1) {
        long sqrt;
        if (x < 41529141369L) {
            int i;
            float x2, y;

            x2 = x * 0.5F;
            y = x;
            i = Float.floatToRawIntBits(y);
            //using the magic number from 
            //http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf
            //since it more accurate
            i = 0x5f375a86 - (i >> 1);
            y = Float.intBitsToFloat(i);
            y = y * (1.5F - (x2 * y * y));
            y = y * (1.5F - (x2 * y * y)); //Newton iteration, more accurate
            sqrt = (long) ((1.0F/y) + 0.2);
        } else {
            //Carmack hack gives incorrect answer for n >= 41529141369.
            sqrt = (long) Math.sqrt(x);
        }
        return sqrt*sqrt == x;
    }
    return false;
}

এবং আমার মানদণ্ডের জোতা: (গুগল ক্যালিপার 0.1-আরসি 5 প্রয়োজন)

public class SquareRootBenchmark {
    public static class Benchmark1 extends SimpleBenchmark {
        private static final int ARRAY_SIZE = 10000;
        long[] trials = new long[ARRAY_SIZE];

        @Override
        protected void setUp() throws Exception {
            Random r = new Random();
            for (int i = 0; i < ARRAY_SIZE; i++) {
                trials[i] = Math.abs(r.nextLong());
            }
        }


        public int timeInternet(int reps) {
            int trues = 0;
            for(int i = 0; i < reps; i++) {
                for(int j = 0; j < ARRAY_SIZE; j++) {
                    if(SquareRootAlgs.isPerfectSquareInternet(trials[j])) trues++;
                }
            }

            return trues;   
        }

        public int timeDurron(int reps) {
            int trues = 0;
            for(int i = 0; i < reps; i++) {
                for(int j = 0; j < ARRAY_SIZE; j++) {
                    if(SquareRootAlgs.isPerfectSquareDurron(trials[j])) trues++;
                }
            }

            return trues;   
        }

        public int timeDurronTwo(int reps) {
            int trues = 0;
            for(int i = 0; i < reps; i++) {
                for(int j = 0; j < ARRAY_SIZE; j++) {
                    if(SquareRootAlgs.isPerfectSquareDurronTwo(trials[j])) trues++;
                }
            }

            return trues;   
        }
    }

    public static void main(String... args) {
        Runner.main(Benchmark1.class, args);
    }
}

আপডেট: আমি একটি নতুন অ্যালগরিদম তৈরি করেছি যা কিছু পরিস্থিতিতে দ্রুততর হয়, অন্যের চেয়ে ধীর গতিতে, আমি বিভিন্ন ইনপুটগুলির উপর ভিত্তি করে বিভিন্ন মানদণ্ড পেয়েছি। যদি আমরা মডুলো গণনা করি 0xFFFFFF = 3 x 3 x 5 x 7 x 13 x 17 x 241, আমরা 97.82% সংখ্যা বাদ দিতে পারি যা স্কোয়ার হতে পারে না। এটি 5 বিটওয়াইড অপারেশন সহ এক লাইনে (সাজানো) করা যেতে পারে:

if (!goodLookupSquares[(int) ((n & 0xFFFFFFl) + ((n >> 24) & 0xFFFFFFl) + (n >> 48))]) return false;

ফলাফল সূচকটি হয় 1) অবশিষ্টাংশ, 2) অবশিষ্টাংশ + 0xFFFFFF, বা 3) অবশিষ্টাংশ + 0x1FFFFFE। অবশ্যই, আমাদের অবশিষ্টাংশের মডুলোর জন্য একটি সারণী থাকা দরকার 0xFFFFFF, যা প্রায় 3 এমবি ফাইলের (এটি ক্ষেত্রে ascii টেক্সট দশমিক সংখ্যা হিসাবে সঞ্চিত থাকে, অনুকূল নয় তবে স্পষ্টভাবে অসম্ভব একটি ByteBufferএবং আরও অনেক কিছু দিয়ে But তবে যেহেতু এটি পূর্বনির্ধারণ হয় না) এত বড় ব্যাপার না আপনি এখানে ফাইলটি খুঁজে পেতে পারেন (বা এটি নিজে তৈরি করুন):

public final static boolean isPerfectSquareDurronThree(long n) {
    if(n < 0) return false;
    if(n == 0) return true;

    long x = n;
    while((x & 0x3) == 0) x >>= 2;
    if((x & 0x7) == 1) {
        if (!goodLookupSquares[(int) ((n & 0xFFFFFFl) + ((n >> 24) & 0xFFFFFFl) + (n >> 48))]) return false;
        long sqrt;
        if(x < 410881L)
        {
            int i;
            float x2, y;

            x2 = x * 0.5F;
            y  = x;
            i  = Float.floatToRawIntBits(y);
            i  = 0x5f3759df - ( i >> 1 );
            y  = Float.intBitsToFloat(i);
            y  = y * ( 1.5F - ( x2 * y * y ) );

            sqrt = (long)(1.0F/y);
        } else {
            sqrt = (long) Math.sqrt(x);
        }
        return sqrt*sqrt == x;
    }
    return false;
}

আমি এটিকে এটির booleanমতো অ্যারেতে লোড করি :

private static boolean[] goodLookupSquares = null;

public static void initGoodLookupSquares() throws Exception {
    Scanner s = new Scanner(new File("24residues_squares.txt"));

    goodLookupSquares = new boolean[0x1FFFFFE];

    while(s.hasNextLine()) {
        int residue = Integer.valueOf(s.nextLine());
        goodLookupSquares[residue] = true;
        goodLookupSquares[residue + 0xFFFFFF] = true;
        goodLookupSquares[residue + 0x1FFFFFE] = true;
    }

    s.close();
}

রানটাইম উদাহরণ। Durronআমি যে দৌড়েছি প্রতিটি পরীক্ষায় এটি হ'ল (সংস্করণ এক)।

 0% Scenario{vm=java, trial=0, benchmark=Internet} 40665.77 ns; ?=566.71 ns @ 10 trials
33% Scenario{vm=java, trial=0, benchmark=Durron} 38397.60 ns; ?=784.30 ns @ 10 trials
67% Scenario{vm=java, trial=0, benchmark=DurronThree} 36171.46 ns; ?=693.02 ns @ 10 trials

  benchmark   us linear runtime
   Internet 40.7 ==============================
     Durron 38.4 ============================
DurronThree 36.2 ==========================

vm: java
trial: 0

3
একটি দৈত্য দেখার টেবিলটি কোনও ভাল ধারণা বলে মনে হচ্ছে না। X86 হার্ডওয়্যার স্কয়ার্ট নির্দেশের (~ 20 চক্র) তুলনায় একটি ক্যাশে মিস ধীর (~ 100 থেকে 150 চক্র)। থ্রুপুট অনুসারে, আপনি প্রচুর অসামান্য ক্যাশে-মিস করতে পারেন তবে আপনি এখনও অন্য দরকারী ডেটা উচ্ছেদ করছেন। অন্য যে কোনও বিকল্পের তুলনায় এটি যদি খুব দ্রুত হয় তবে একটি বিশাল সন্ধানের টেবিলটি তখনই তার পক্ষে মূল্যবান হতে পারে এবং আপনার পুরো প্রোগ্রামটির পারফরম্যান্সে এই ফাংশনটি ছিল প্রধান ফ্যাক্টর।
পিটার কর্ডেস

1
@SwissFrank: নিখুঁত-বর্গক্ষেত্র চেক করা হয় শুধুমাত্র জিনিস আপনার প্রোগ্রাম করে? একটি সন্ধানের টেবিলটি এমন একটি মাইক্রোব্যাঙ্কমার্কে দেখতে বেশ ভাল লাগতে পারে যা একে বারে টাইট লুপে ডাকে, কিন্তু একটি বাস্তব প্রোগ্রামে যার কার্যক্ষমতার অন্যান্য ডেটা রয়েছে, এটি ভাল নয় good
পিটার কর্ডেস

1
0x1FFFFFE বিটের একটি বিটম্যাপ একটি প্যাক বিটম্যাপ হিসাবে সঞ্চিত থাকলে 4 মেগা- বাইট লাগে । একটি আধুনিক ইনটেল ডেস্কটপে একটি এল 3 ক্যাশে হিট হয়েছে> 40 টি চক্রের বিলম্ব এবং আরও বড় জিয়োন এর চেয়ে খারাপ; হার্ডওয়্যার স্কয়ার + মাল্ট লেটেন্সি থেকে দীর্ঘ longer যদি প্রতি মান 1 বাইট সহ বাইট- ম্যাপ হিসাবে সংরক্ষণ করা হয় তবে এটি প্রায় 32 এমবি; যে কোনও কিছুর L3 ক্যাশে ছাড়াও অনেকগুলি মূল কোর সিওন যেখানে সমস্ত কোর একটি বিশাল ক্যাশে ভাগ করে। সুতরাং যদি আপনার ইনপুটগুলির ডেটার একটি বৃহত পরিমাণ ইনপুটগুলির তুলনায় অভিন্ন র্যান্ডম বিতরণ থাকে তবে আপনি একটি টান লুপেও প্রচুর এল 2 ক্যাশে মিস করবেন না। (ইনটেলের উপর প্রতি-কোর এল 2 ব্যক্তিগত মাত্র 256 কে, 12 ডলার চক্রের বিলম্বের সাথে))
পিটার কর্ডস

1
@ সুইসফ্র্যাঙ্ক: ওহ, আপনি যদি যা করছেন সবই যদি রুট চেকিং হয় তবে বি 3 মানচিত্রের এল 3 হিট পাওয়ার সম্ভাবনা রয়েছে। আমি বিলম্বের দিকে তাকিয়ে ছিলাম, তবে অনেকগুলি মিস করা একবারে ফ্লাইটে যেতে পারে, তাই থ্রুপুট সম্ভাব্য ভাল। ওটিওএইচ, সিমডি sqrtpsথ্রুপুট বা এমনকি sqrtpd(ডাবল-প্রিসিশন) স্কাইলেকে খুব খারাপ নয়, তবে পুরানো সিপিইউগুলিতে বিলম্বের চেয়ে বেশি ভাল নয়। যাইহোক 7-cpu.com/cpu/Haswell.html এর কয়েকটি দুর্দান্ত পরীক্ষামূলক নম্বর এবং অন্যান্য সিপিইউগুলির জন্য পৃষ্ঠা রয়েছে। অগ্নার ফগের মাইক্রোয়ার্ক গাইড পিডিএফ-তে ইন্টেল এবং এএমডি uarches এর জন্য কিছু ক্যাশে লেটেন্সি নম্বর রয়েছে: agner.org/optimize
পিটার

1
জাভা থেকে x86 সিমডি ব্যবহার করা একটি সমস্যা এবং আপনি যখন ইনটি-> এফপি এবং এফপি-> ইন্ট রূপান্তরকরণের ব্যয় যোগ করবেন তখন এটি বিস্মৃত হয় যে বিটম্যাপটি আরও ভাল হতে পারে। doubleকিছু সংখ্যক + -2 ^ 24 সীমার বাইরে গোল করা এড়াতে আপনার যথাযথতা প্রয়োজন (যাতে 32-বিট পূর্ণসংখ্যা এর বাইরেও হতে পারে), এবং নির্দেশ অনুসারে কেবলমাত্র অনেকগুলি উপাদানকে অর্ধেক প্রক্রিয়াকরণ করার sqrtpdচেয়ে ধীর করে দেয় sqrtps(প্রতি সিমড ভেক্টর) ।
পিটার কর্ডেস

18

পূর্ণসংখ্যার স্কোয়ার রুট গণনা করার জন্য নিউটনের পদ্ধতিটি ব্যবহার করা আরও দ্রুত হওয়া উচিত , তারপরে এই সংখ্যাটি বর্গক্ষেত্র করুন এবং আপনার বর্তমান সমাধান হিসাবে যাচাই করুন check নিউটনের পদ্ধতি হ'ল কিছু অন্যান্য উত্তরে উল্লিখিত কারম্যাক সমাধানের ভিত্তি। আপনি কেবলমাত্র শিকড়টির পূর্ণসংখ্যার অংশে আগ্রহী, আপনাকে আরও দ্রুততর অ্যালগোরিদম বন্ধ করার অনুমতি দেয় বলে একটি দ্রুত উত্তর পেতে সক্ষম হওয়া উচিত।

আপনি চেষ্টা করতে পারেন এমন আরও একটি অপ্টিমাইজেশন: যদি কোনও সংখ্যার ডিজিটাল রুটটি 1, 4, 7 বা 9 এ শেষ না হয় তবে সংখ্যাটি একটি নিখুঁত বর্গ নয়। ধীর স্কোয়ার রুট অ্যালগরিদম প্রয়োগ করার আগে আপনার 60% ইনপুটগুলি অপসারণের দ্রুত উপায় হিসাবে এটি ব্যবহার করা যেতে পারে।


1
ডিজিটাল রুটটি কঠোরভাবে গণনামূলকভাবে মডুলোর সমতুল্য, সুতরাং এখানে অন্যান্য মডুলো পদ্ধতির সাথে যেমন মোড 16 এবং মোড 255 হিসাবে বিবেচনা করা উচিত
খ্রিস্টান ওডার্ড

1
আপনি কি ডিজিটাল মূলটি মডুলোর সমতুল্য? লিঙ্কটি দ্বারা ব্যাখ্যা করা হিসাবে এটি সম্পূর্ণ আলাদা কিছু বলে মনে হচ্ছে। লক্ষ করুন তালিকাটি 1,4,7,9 নয় 1,4,5,9।
ফ্র্যাক্টালি

1
দশমিক সিস্টেমে ডিজিটাল রুট মডুলো 9 (ওয়েল ডার (এন) = 1 + ((এন -1) মডেল 9) ব্যবহারের সমতুল্য; সুতরাং একটি সামান্য শিফটও))। 0,1,4,5,9 নম্বরগুলি মডুলো 16 এর জন্য, এবং 0, 1, 4, 7 মডুলো 9 এর জন্য - যা ডিজিটাল মূলের জন্য 1, 4, 7, 9 এর সমান।
হ্যানস ওলসন

16

আমি চাই এই ফাংশনটি সমস্ত ইতিবাচক -৪-বিট স্বাক্ষরিত পূর্ণসংখ্যার সাথে কাজ করে

Math.sqrt()ইনপুট পরামিতি হিসাবে ডাবলসের সাথে কাজ করে, তাই আপনি 2 ^ 53 এর চেয়ে বড় পূর্ণসংখ্যার জন্য সঠিক ফলাফল পাবেন না ।


5
আমি প্রকৃতপক্ষে 2 ^ 53 এর চেয়ে বড় সমস্ত নিখুঁত স্কোয়ারের উত্তরটি পরীক্ষা করেছি, পাশাপাশি প্রতিটি নিখুঁত বর্গের নীচে 5 থেকে প্রতিটি নিখুঁত বর্গের উপরে 5 পর্যন্ত সমস্ত সংখ্যা রয়েছে এবং আমি সঠিক ফলাফল পেয়েছি। (রাউন্ডঅফ ত্রুটিটি সংশোধন করা হয় যখন আমি দীর্ঘায়িত স্কয়ারটি উত্তরটি গোল করি, তারপরে যে মানটি এবং তুলনা করি)
কিপ

2
@Kip: আমি প্রমাণিত করেছি যে এটি কাজ করে
মার্টিনাস

ফলাফলগুলি পুরোপুরি নির্ভুল নয়, তবে আপনি যা ভাবেন তার চেয়ে বেশি নির্ভুল। যদি আমরা রূপান্তর দ্বিগুণ হওয়ার পরে এবং বর্গমূলের পরে কমপক্ষে 15 টি সঠিক সংখ্যা ধরে নিই, তবে এটি যথেষ্ট because নিকটতম +0.5 রাউন্ড।
mwfearnley

3
ম্যাথ.এসকিআরটি () সম্পূর্ণ নির্ভুল নয়, তবে এটির দরকার নেই। প্রথম পোস্টে, টিএসটি স্কয়ারটি (এন) এর কাছাকাছি একটি পূর্ণসংখ্যা। N যদি বর্গক্ষেত্র না হয় তবে tst * tst! = N, tst এর মান যাই হোক না কেন। যদি N একটি নিখুঁত বর্গ হয়, তবে স্কয়ার্ট (এন) <2 ^ 32, এবং যতক্ষণ পর্যন্ত স্ক্রুটি (এন) একটি ত্রুটি <0.5 এর সাথে গণনা করা হয়, আমরা ভাল।
gnasher729

13

কেবল রেকর্ডের জন্য, অন্য পন্থাটি হ'ল প্রধান পচন ব্যবহার করা। পচনগুলির প্রতিটি উপাদান যদি সমান হয় তবে সংখ্যাটি একটি নিখুঁত বর্গ। সুতরাং আপনি যা দেখতে চান তা হল কোনও সংখ্যাকে মৌলিক সংখ্যার স্কোয়ারের পণ্য হিসাবে পচন করা যায়। অবশ্যই, আপনার এ জাতীয় পচনের দরকার নেই, কেবল এটি বিদ্যমান কিনা তা দেখার জন্য।

প্রথমে মূল সংখ্যার স্কোয়ারের একটি টেবিল তৈরি করুন যা 2 ^ 32 এর চেয়ে কম। এটি এই সীমা পর্যন্ত সমস্ত পূর্ণসংখ্যার টেবিলের চেয়ে অনেক ছোট।

একটি সমাধান তারপর এই মত হবে:

boolean isPerfectSquare(long number)
{
    if (number < 0) return false;
    if (number < 2) return true;

    for (int i = 0; ; i++)
    {
        long square = squareTable[i];
        if (square > number) return false;
        while (number % square == 0)
        {
            number /= square;
        }
        if (number == 1) return true;
    }
}

আমার ধারণা এটি কিছুটা রহস্যজনক। এটি যা করে তা প্রতিটি পদক্ষেপে যাচাই করা হয় যে একটি মৌলিক সংখ্যার বর্গক্ষেত্র ইনপুট নম্বরকে বিভক্ত করে। যদি এটি হয় তবে এটি প্রাথমিক পচন থেকে এই বর্গক্ষেত্রটিকে সরিয়ে ফেলার জন্য যতক্ষণ সম্ভব এটি বর্গ দ্বারা সংখ্যাটিকে বিভক্ত করে। যদি এই প্রক্রিয়া দ্বারা, আমরা 1 এ এসেছি, তবে ইনপুট সংখ্যাটি মূল সংখ্যার বর্গক্ষেত্রের ক্ষয় ছিল। বর্গটি যদি সংখ্যার চেয়ে বড় হয়ে যায় তবে এই বর্গ বা কোনও বৃহত্তর স্কোয়ারের কোনও উপায় নেই, এটি ভাগ করতে পারে, সুতরাং সংখ্যাটি মৌলিক সংখ্যার স্কোয়ারের ক্ষয় হতে পারে না।

আজকাল হার্ডওয়্যারে সম্পন্ন স্কয়ার্ট এবং এখানে প্রাথমিক সংখ্যার গণনা করা প্রয়োজন, আমার ধারণা এই সমাধানটি ধীর। তবে স্কয়ার্টের সাথে সমাধানের চেয়ে এটি আরও ভাল ফলাফল দেওয়া উচিত যা 2 ^ 54 এর বেশি কাজ করবে না, যেমনটি তাঁর উত্তরে এমআরজিএল বলেছেন।


1
পূর্ণসংখ্যা বিভাগ বর্তমান হার্ডওয়্যারে এফপি স্কয়ার্টের চেয়ে ধীর। এই ধারণার কোনও সুযোগ নেই। >। <২০০৮ সালেও কোর 2 এর sqrtsdথ্রুপুট 6-58c প্রতি এক। এটি idiv12-36 সাইকেল প্রতি এক। (থ্রোপুটগুলির মতো অনুরূপ বিলম্ব: কোনও ইউনিট পাইপলাইনযুক্ত নয়)।
পিটার কর্ডেস

স্কয়ারটি পুরোপুরি নির্ভুল হওয়ার দরকার নেই। এজন্য ফলাফলটি স্কোয়ার করে এবং পূর্ণসংখ্যা-পরীক্ষা করে ইনপুট পূর্ণসংখ্যটির সঠিক কোনও পূর্ণসংখ্য স্কয়ারটি আছে কিনা তা নির্ধারণ করতে আপনি পরীক্ষা করে দেখেন।
পিটার কর্ডেস

11

এটি নির্দিষ্ট করা হয়েছে যে dএকটি নিখুঁত বর্গক্ষেত্রের শেষ অঙ্কগুলি কেবল নির্দিষ্ট মানগুলিতে গ্রহণ করতে পারে। কোনও dসংখ্যার শেষ সংখ্যা (বেসে b) nবাকী অংশগুলির সমান, যখন nভাগ করা হয় bd, অর্থাৎ। সি স্বরলিপি n % pow(b, d)

এটি যেকোন মডুলাসে সাধারণীকরণ করা যায় m, অর্থাত্‍। n % mনিখুঁত স্কোয়ার হতে কিছু শতাংশ সংখ্যার বিধান ব্যবহার করতে ব্যবহার করা যেতে পারে। আপনি বর্তমানে যে মডুলাসটি ব্যবহার করছেন সেটি হ'ল 64, যা 12, অর্থাৎ অনুমতি দেয়। 19% অবশিষ্টাংশ, সম্ভাব্য স্কোয়ার হিসাবে। সামান্য কোডিংয়ের সাথে আমি মডুলাসটি 110880 পেয়েছি, যা কেবলমাত্র 2016 এর অনুমতি দেয়। সম্ভাব্য স্কোয়ার হিসাবে অবশিষ্টদের 1.8%। সুতরাং একটি মডুলাস অপারেশন (যেমন। বিভাগ) এবং আপনার মেশিনে একটি বর্গমূলের তুলনায় একটি সারণী অনুসন্ধানের ব্যয়ের উপর নির্ভর করে এই মডুলাসটি ব্যবহার করা আরও দ্রুত হতে পারে।

যাইহোক জাভা যদি লুকিং টেবিলের জন্য বিটগুলির একটি প্যাকযুক্ত অ্যারে সঞ্চয় করার উপায় রাখে তবে এটি ব্যবহার করবেন না। 110880 32-বিট শব্দগুলি আজকাল খুব বেশি র‍্যাম নয় এবং একটি মেশিন শব্দটি আনতে একটি বিট আনার চেয়ে দ্রুত হতে চলেছে।


খুশী হলাম। আপনি কি বীজগণিত হিসাবে বা পরীক্ষা এবং ত্রুটির দ্বারা কাজ করেছেন? এটি এত কার্যকর কেন আমি দেখতে পাচ্ছি - নিখুঁত স্কোয়ারগুলির মধ্যে প্রচুর সংঘর্ষ, উদাহরণস্বরূপ 333 ^ 2% 110880 == 3 ^ 2, 334 ^ 2% 110880 == 26 ^ 2, 338 ^ 2% 110880 == 58 ^ 2 ..
finnw

আইআইআরসি এটি নিষ্ঠুর শক্তি ছিল, তবে লক্ষ করুন যে 110880 = 2 ^ 5 * 3 ^ 2 * 5 * 7 * 11, যা 6 * 3 * 2 * 2 * 2 - 1 = 143 যথাযথ বিভাজন দেয়।
হিউ অ্যালেন

আমি খুঁজে পেয়েছি যে সন্ধানের সীমাবদ্ধতার কারণে, ২৪. pass% পাশের হারের সাথে 44352 আরও ভাল কাজ করে। কমপক্ষে আমার বাস্তবায়নে।
ফ্র্যাক্টালি

1
পূর্ণসংখ্যা বিভাগ ( idiv) sqrtsdবর্তমান x86 হার্ডওয়্যারে এফপি স্কয়ার্ট ( ) এর তুলনায় সমান বা খারাপ । এছাড়াও, বিটফিল্ডগুলি এড়িয়ে যাওয়ার সাথে সম্পূর্ণ একমত নয়। ক্যাচ হিট রেট বিটফিল্ডের সাথে টন আরও ভাল হবে এবং বিটফিল্ডে কিছুটা পরীক্ষা করা পুরো বাইট পরীক্ষা করার চেয়ে কেবল এক বা দুটি আরও সহজ নির্দেশ। (ছোট্ট টেবিল এমনকি অ-bitfields ক্যাশের মধ্যে মাপসই, একটি বাইট অ্যারের সেরা হবে, আপনি ints না 32bit X86 32bit DWORD সমান গতিতে একক বাইট অ্যাক্সেস আছে।।)
পিটার Cordes

11

একটি পূর্ণসংখ্যা সমস্যা পূর্ণসংখ্যা সমাধানের দাবি রাখে। এইভাবে

এরকম সবচেয়ে বড় পূর্ণসংখ্যার সন্ধান করতে (অ-নেতিবাচক) পূর্ণসংখ্যার উপর বাইনারি অনুসন্ধান করুন t**2 <= n। তারপরে r**2 = nঠিক আছে কিনা পরীক্ষা করুন । এটি সময় নেবে O (লগ এন)।

সেটটি আনবাউন্ডেড হওয়ার কারণে আপনি কীভাবে ইতিবাচক পূর্ণসংখ্যার সন্ধান করতে জানেন না, এটি সহজ। আপনি আপনার f(t) = t**2 - nদুটির শক্তিতে ক্রমবর্ধমান ফাংশন (উপরে ) গণনা করে শুরু করছেন । আপনি যখন এটি ইতিবাচক দিকে দেখেন, আপনি একটি উপরের সীমাটি পেয়েছেন। তারপরে আপনি স্ট্যান্ডার্ড বাইনারি অনুসন্ধান করতে পারেন।


প্রকৃতপক্ষে সময়টি কমপক্ষে হবে O((log n)^2)কারণ গুণনটি ধ্রুবক-সময় নয় তবে বাস্তবে এর সীমাবদ্ধতা থাকে O(log n)যা বৃহত্তর বহু-নির্ভুলতার সংখ্যার সাথে কাজ করার সময় স্পষ্ট হয়। তবে এই উইকের ক্ষেত্রটি -৪-বিট বলে মনে হচ্ছে, তাই এটি এনবিডি হতে পারে।

10

মার্টিনাসের সমাধানের নীচের সরলকরণটি রানটাইম থেকে কয়েক শতাংশ পয়েন্ট শেভ করতে দেখা যায়, তবে আমি বিশ্বাস করতে পারি এমন একটি বেঞ্চমার্ক তৈরি করার জন্য আমি বেঞ্চমার্কিংয়ে যথেষ্ট ভাল নই:

long goodMask; // 0xC840C04048404040 computed below
{
    for (int i=0; i<64; ++i) goodMask |= Long.MIN_VALUE >>> (i*i);
}

public boolean isSquare(long x) {
    // This tests if the 6 least significant bits are right.
    // Moving the to be tested bit to the highest position saves us masking.
    if (goodMask << x >= 0) return false;
    // Remove an even number of trailing zeros, leaving at most one.
    x >>= (Long.numberOfTrailingZeros(x) & (-2);
    // Repeat the test on the 6 least significant remaining bits.
    if (goodMask << x >= 0 | x <= 0) return x == 0;
    // Do it in the classical way.
    // The correctness is not trivial as the conversion from long to double is lossy!
    final long tst = (long) Math.sqrt(x);
    return tst * tst == x;
}

এটি প্রথম পরীক্ষার বাদ দিয়ে কীভাবে পরীক্ষা করা উচিত,

if (goodMask << x >= 0) return false;

কর্মক্ষমতা প্রভাবিত করবে।


2
ফলাফল এখানে । প্রথম টেস্টটি সরিয়ে ফেলা খারাপ কারণ এটি বেশিরভাগ ক্ষেত্রেই বেশ সস্তায় সমাধান করে। উত্সটি আমার উত্তরে (আপডেট হয়েছে)।
মার্টিনাস

9

পারফরম্যান্সের জন্য, আপনাকে বেশিরভাগ ক্ষেত্রে কিছু সংক্ষেপণ করতে হয়। অন্যরা বিভিন্ন পদ্ধতি প্রকাশ করেছেন, তবে, আপনি লক্ষ করেছেন যে কারম্যাকের হ্যাকটি এন এর কয়েকটি নির্দিষ্ট মান পর্যন্ত দ্রুত ছিল Then উত্তর এখানে।


আমি আপনার পরামর্শটি সমাধানেও অন্তর্ভুক্ত করেছি। এছাড়াও, দুর্দান্ত হ্যান্ডেল :)
কিপ করুন

8

এই থ্রেডে অন্যদের দ্বারা প্রস্তাবিত কৌশলগুলির সংমিশ্রণটি ব্যবহার করে এটি আমি দ্রুততম জাভা বাস্তবায়ন নিয়ে আসতে পারি।

  • Mod-256 পরীক্ষা
  • নিখরচায় Mod-3465 পরীক্ষা (কিছু মিথ্যা ধনাত্মক মূল্যের জন্য পূর্ণসংখ্যা বিভাগ এড়ানো)
  • ফ্লোটিং-পয়েন্ট বর্গমূল, গোল এবং ইনপুট মানের সাথে তুলনা করুন

আমি এই পরিবর্তনগুলি নিয়ে পরীক্ষাও করেছি কিন্তু তারা পারফরম্যান্সে সহায়তা করেনি:

  • অতিরিক্ত Mod-255 পরীক্ষা
  • 4 এর পাওয়ার দ্বারা ইনপুট মান ভাগ করা
  • দ্রুত বিপরীত স্কোয়ার রুট (এন এর উচ্চ মানের জন্য কাজ করতে এটির 3 টি পুনরাবৃত্তি প্রয়োজন, এটি হার্ডওয়ার স্কোয়ার রুট ফাংশনের চেয়ে ধীর করে দেওয়ার জন্য যথেষ্ট))

public class SquareTester {

    public static boolean isPerfectSquare(long n) {
        if (n < 0) {
            return false;
        } else {
            switch ((byte) n) {
            case -128: case -127: case -124: case -119: case -112:
            case -111: case -103: case  -95: case  -92: case  -87:
            case  -79: case  -71: case  -64: case  -63: case  -60:
            case  -55: case  -47: case  -39: case  -31: case  -28:
            case  -23: case  -15: case   -7: case    0: case    1:
            case    4: case    9: case   16: case   17: case   25:
            case   33: case   36: case   41: case   49: case   57:
            case   64: case   65: case   68: case   73: case   81:
            case   89: case   97: case  100: case  105: case  113:
            case  121:
                long i = (n * INV3465) >>> 52;
                if (! good3465[(int) i]) {
                    return false;
                } else {
                    long r = round(Math.sqrt(n));
                    return r*r == n; 
                }
            default:
                return false;
            }
        }
    }

    private static int round(double x) {
        return (int) Double.doubleToRawLongBits(x + (double) (1L << 52));
    }

    /** 3465<sup>-1</sup> modulo 2<sup>64</sup> */
    private static final long INV3465 = 0x8ffed161732e78b9L;

    private static final boolean[] good3465 =
        new boolean[0x1000];

    static {
        for (int r = 0; r < 3465; ++ r) {
            int i = (int) ((r * r * INV3465) >>> 52);
            good3465[i] = good3465[i+1] = true;
        }
    }

}

7

আপনার শুরু থেকেই N এর 2-পাওয়ার অংশটি থেকে মুক্তি পাওয়া উচিত।

2 য় সম্পাদনা নীচে মিটার জন্য icalন্দ্রজালিক ভাবটি হওয়া উচিত

m = N - (N & (N-1));

এবং লিখিত হিসাবে না

২ য় সম্পাদনার সমাপ্তি

m = N & (N-1); // the lawest bit of N
N /= m;
byte = N & 0x0F;
if ((m % 2) || (byte !=1 && byte !=9))
  return false;

1 ম সম্পাদনা:

গৌণ উন্নতি:

m = N & (N-1); // the lawest bit of N
N /= m;
if ((m % 2) || (N & 0x07 != 1))
  return false;

1 ম সম্পাদনার সমাপ্তি

এখন যথারীতি চালিয়ে যান। এইভাবে, আপনি ভাসমান পয়েন্ট অংশে পৌঁছানোর সময়, আপনি ইতিমধ্যে সমস্ত সংখ্যাটি থেকে মুক্তি পেয়েছেন যার 2-পাওয়ার অংশটি বিজোড় (প্রায় অর্ধেক), এবং তারপরে আপনি কেবল যা বাকী রেখেছেন তার 1/8 অংশ বিবেচনা করবেন। অর্থাৎ আপনি 6% সংখ্যার উপর ভাসমান পয়েন্ট অংশটি চালান।


7

প্রজেক্ট অলারের ট্যাগগুলিতে উল্লিখিত এবং এতে থাকা অনেকগুলি সমস্যার জন্য পরীক্ষার নম্বর প্রয়োজন >> 2^64। আপনি উল্লিখিত বেশিরভাগ অপ্টিমাইজেশনগুলি যখন আপনি ৮০ বাইট বাফারের সাথে কাজ করছেন তখন সহজেই কাজ করে না।

আমি জাভা বিগইন্টেজার এবং নিউটনের পদ্ধতির সামান্য পরিবর্তিত সংস্করণ ব্যবহার করেছি, এটি পূর্ণসংখ্যার সাথে আরও ভাল কাজ করে। সমস্যা হল সঠিক স্কোয়ার ছিল n^2থেকে converged (n-1)পরিবর্তে nকারণ n^2-1 = (n-1)(n+1)এবং চূড়ান্ত ত্রুটি চূড়ান্ত ভাজক নিচে মাত্র এক ধাপ এবং আলগোরিদিম বন্ধ হয়েছে। ত্রুটি গণনার আগে মূল যুক্তিতে একটি যুক্ত করে এটি ঠিক করা সহজ হয়েছিল। (কিউব শিকড় ইত্যাদির জন্য দুটি যোগ করুন)

এই অ্যালগরিদমের একটি দুর্দান্ত বৈশিষ্ট্য হ'ল আপনি তাৎক্ষণিকভাবে বলতে পারবেন যে সংখ্যাটি একটি নিখুঁত বর্গক্ষেত্র - নিউটনের পদ্ধতিতে চূড়ান্ত ত্রুটি (সংশোধন নয়) হবে শূন্য। একটি সাধারণ পরিবর্তন আপনাকে floor(sqrt(x))নিকটতম পূর্ণসংখ্যার পরিবর্তে দ্রুত গণনা করতে দেয় । এটি বেশ কয়েকটি এলিউর সমস্যা সহকারে কার্যকর।


1
আমি এই অ্যালগরিদমগুলি সম্পর্কে বহু-নির্ভুলতা বাফারগুলিতে ভাল অনুবাদ না করে সম্পর্কে একই কথা ভাবছিলাম। সুতরাং ভেবেছি আমি এটি এখানেই আটকে রেখেছি ... আমি প্রকৃতপক্ষে বিপুল সংখ্যার জন্য আরও ভাল অ্যাসিপটোটিক জটিলতার সাথে একটি সম্ভাব্য স্কোয়ারনেস পরীক্ষা পেয়েছি ..... যেখানে সংখ্যার তত্ত্বের অ্যাপ্লিকেশনগুলি তাদের খুঁজে পাওয়া যায় না om প্রকল্প ইউলারের সাথে পরিচিত না হলেও ... আকর্ষণীয় দেখাচ্ছে looks

6

এটি রুবিতে, দশমিক থেকে পুরাতন মার্চেন্ট ক্যালকুলেটর অ্যালগরিদমের বাইনারি পর্যন্ত পুনঃনির্ধারণ (দুঃখিত, আমার কোনও উল্লেখ নেই), এই প্রশ্নের জন্য বিশেষভাবে অভিযোজিত:

def isexactsqrt(v)
    value = v.abs
    residue = value
    root = 0
    onebit = 1
    onebit <<= 8 while (onebit < residue)
    onebit >>= 2 while (onebit > residue)
    while (onebit > 0)
        x = root + onebit
        if (residue >= x) then
            residue -= x
            root = x + onebit
        end
        root >>= 1
        onebit >>= 2
    end
    return (residue == 0)
end

এখানে অনুরূপ কিছুটির একটি ওয়ার্কআপ রয়েছে (দয়া করে কোডিং শৈলী / গন্ধ বা ক্লানকি ও / ও-র জন্য আমাকে ভোট দিন না - এটি গণনা করা অ্যালগরিদম, এবং সি ++ আমার হোম ভাষা নয়)। এই ক্ষেত্রে, আমরা অবশিষ্টাংশগুলি খুঁজছি == 0:

#include <iostream>  

using namespace std;  
typedef unsigned long long int llint;

class ISqrt {           // Integer Square Root
    llint value;        // Integer whose square root is required
    llint root;         // Result: floor(sqrt(value))
    llint residue;      // Result: value-root*root
    llint onebit, x;    // Working bit, working value

public:

    ISqrt(llint v = 2) {    // Constructor
        Root(v);            // Take the root 
    };

    llint Root(llint r) {   // Resets and calculates new square root
        value = r;          // Store input
        residue = value;    // Initialise for subtracting down
        root = 0;           // Clear root accumulator

        onebit = 1;                 // Calculate start value of counter
        onebit <<= (8*sizeof(llint)-2);         // Set up counter bit as greatest odd power of 2 
        while (onebit > residue) {onebit >>= 2; };  // Shift down until just < value

        while (onebit > 0) {
            x = root ^ onebit;          // Will check root+1bit (root bit corresponding to onebit is always zero)
            if (residue >= x) {         // Room to subtract?
                residue -= x;           // Yes - deduct from residue
                root = x + onebit;      // and step root
            };
            root >>= 1;
            onebit >>= 2;
        };
        return root;                    
    };
    llint Residue() {           // Returns residue from last calculation
        return residue;                 
    };
};

int main() {
    llint big, i, q, r, v, delta;
    big = 0; big = (big-1);         // Kludge for "big number"
    ISqrt b;                            // Make q sqrt generator
    for ( i = big; i > 0 ; i /= 7 ) {   // for several numbers
        q = b.Root(i);                  // Get the square root
        r = b.Residue();                // Get the residue
        v = q*q+r;                      // Recalc original value
        delta = v-i;                    // And diff, hopefully 0
        cout << i << ": " << q << " ++ " << r << " V: " << v << " Delta: " << delta << "\n";
    };
    return 0;
};

পুনরাবৃত্তির সংখ্যা O (ln n) দেখায়, যেখানে n এর বিট-দৈর্ঘ্য, সুতরাং আমি সন্দেহ করি এটি বৃহত্তর ভি এর জন্য অনেক কিছু সাশ্রয় করবে ভাসমান পয়েন্ট বর্গাকারটি ধীর, সম্ভবত 100-200 চক্র, তবে পূর্ণসংখ্যার গণিতটি নয় হয় বিনামূল্যে। প্রতিটি 15 টি চক্র সহ এক ডজন পুনরাবৃত্তি, এবং এটি ধোয়া হবে। তবুও, আকর্ষণীয় হওয়ার জন্য +1।
টাদমাস

আসলে, আমি বিশ্বাস করি যে এক্সওআর দ্বারা সংযোজন এবং বিয়োগগুলি করা যেতে পারে।
ব্রেন্ট.লংবোরো

এটি একটি খাঁটি মন্তব্য ছিল - কেবলমাত্র একটি এক্সওআর দ্বারা সংযোজন করা যেতে পারে; বিয়োগটি গাণিতিক।
ব্রেন্ট.লংবোরো

1
এক্সওআর রান রান সময় এবং যাহোক যাইহোক যোগ করার মধ্যে সত্যই কোনও পার্থক্য আছে?
তাদমাস

1
@ টেডমাস: সম্ভবত "পরে অনুকূলিতকরণ" নিয়মটি ভাঙ্গার পক্ষে যথেষ্ট নয়। (:-)
ব্রেন্ট.লংবোরো

6

স্কয়ার্ট কলটি পুরোপুরি নির্ভুল নয়, যেমনটি উল্লেখ করা হয়েছে, তবে এটি আকর্ষণীয় এবং শিক্ষণীয় যে এটি গতির দিক থেকে অন্যান্য উত্তরগুলি উড়িয়ে দেয় না। সর্বোপরি, স্কয়ার্টের জন্য সমাবেশ ভাষার নির্দেশাবলীর ক্রমটি খুব ছোট। ইন্টেলের একটি হার্ডওয়্যার নির্দেশিকা রয়েছে, যা জাভা বিশ্বাস করে না কারণ এটি আইইইই এর সাথে মানায় না।

তাহলে এটা কেন ধীর? কারণ জাভা আসলে জেএনআই এর মাধ্যমে সি রুটিন কল করছে এবং জাভা সাবরুটিন কল করার চেয়ে এটি করা আসলে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে কম। এটি অত্যন্ত বিরক্তিকর, এবং জাভা আরও ভাল সমাধান নিয়ে আসা উচিত ছিল, অর্থাত্ যদি প্রয়োজন হয় তবে ভাসমান পয়েন্ট লাইব্রেরি কলগুলিতে বিল্ডিং করা উচিত। আচ্ছা ভালো.

সি ++ তে, আমি সন্দেহ করি যে সমস্ত জটিল বিকল্পগুলি গতিতে হারাবে, তবে আমি সেগুলি সব পরীক্ষা করে দেখিনি। আমি যা করেছি, এবং জাভা লোকেরা কীভাবে দরকারী ব্যবহার করবে তা হ'ল একটি সাধারণ হ্যাক, এ। রেক্সের প্রস্তাবিত বিশেষ কেস পরীক্ষার একটি এক্সটেনশন। বিট অ্যারে হিসাবে একটি একক দীর্ঘ মান ব্যবহার করুন, যা সীমাবদ্ধ নয় checked এইভাবে, আপনার কাছে 64 বিট বুলিয়ান লুক রয়েছে।

typedef unsigned long long UVLONG
UVLONG pp1,pp2;

void init2() {
  for (int i = 0; i < 64; i++) {
    for (int j = 0; j < 64; j++)
      if (isPerfectSquare(i * 64 + j)) {
    pp1 |= (1 << j);
    pp2 |= (1 << i);
    break;
      }
   }
   cout << "pp1=" << pp1 << "," << pp2 << "\n";  
}


inline bool isPerfectSquare5(UVLONG x) {
  return pp1 & (1 << (x & 0x3F)) ? isPerfectSquare(x) : false;
}

রুটিনটি হল পুরোপুরি স্কুয়ার 5 আমার কোর 2 জুটি মেশিনে প্রায় 1/3 বার চলে। আমি সন্দেহ করি যে একই লাইনের সাথে আরও টুইটগুলি গড় সময়কে আরও কমিয়ে আনতে পারে তবে প্রতিবার আপনি যাচাই করবেন, আপনি আরও নির্মূলের জন্য আরও পরীক্ষার বাণিজ্য করছেন, সুতরাং আপনি সেই রাস্তায় খুব বেশি দূরে যেতে পারবেন না।

অবশ্যই, নেতিবাচক জন্য পৃথক পরীক্ষা না করে আপনি একইভাবে উচ্চ 6 বিট পরীক্ষা করতে পারেন।

মনে রাখবেন যে আমি যা করছি তা সম্ভাব্য স্কোয়ারগুলি মুছে ফেলা হচ্ছে, তবে যখন আমার কোনও সম্ভাব্য কেস হয় তখন আমাকে মূল, ইনলাইনড ইস্পেক্টেক্টস্কয়ারকে কল করতে হয়।

পিপি 1 এবং পিপি 2 এর স্ট্যাটিক মানগুলি শুরু করার জন্য একবার init2 রুটিনকে ডাকা হয়। মনে রাখবেন যে সি ++ তে আমার প্রয়োগের ক্ষেত্রে, আমি স্বাক্ষরবিহীন দীর্ঘ দীর্ঘ ব্যবহার করছি, সুতরাং আপনি স্বাক্ষরিত হওয়ায় আপনাকে >>> অপারেটরটি ব্যবহার করতে হবে।

অ্যারে চেক করার কোনও অভ্যন্তরীণ প্রয়োজন নেই, তবে জাভার অপ্টিমাইজারকে এই জিনিসটি খুব দ্রুত খুঁজে বের করতে হবে, সুতরাং আমি তাদের জন্য দোষ দেব না।


3
আমি বাজি ধরছি তুমি দু'বার ভুল করেছ। 1. ইন্টেল স্কয়ার্ট আইইইই এর সাথে সামঞ্জস্য করে। অ-যুক্তিযুক্ত নির্দেশাবলী হ'ল ল্যাঞ্জ আর্গুমেন্টগুলির গনিওমেট্রিকাল নির্দেশাবলী। ২. জাভা ম্যাথ.এসকিআর্টির জন্য অন্তর্নিহিত ব্যবহার করে, কোনও জেএনআই নেই
মার্টিনাস

1
আপনি ব্যবহার করতে ভুলবেন না pp2? আমি বুঝতে পারি যে pp1এটি ছয়টি অন্তত গুরুত্বপূর্ণ বিট পরীক্ষার জন্য ব্যবহৃত হয়, তবে আমি বিশ্বাস করি না যে পরবর্তী ছয়টি বিট পরীক্ষার ফলে কোনও লাভ হয়।
মার্টিনাস

6

আমি কিছু ইনপুটটিতে প্রায় সঠিক পদ্ধতি ব্যবহার করার ধারণাটি পছন্দ করি। এখানে একটি উচ্চতর "অফসেট" সহ একটি সংস্করণ রয়েছে। কোডটি কাজ করছে বলে মনে হচ্ছে এবং আমার সাধারণ পরীক্ষার কেসটি পাস করেছে।

শুধু আপনার প্রতিস্থাপন:

if(n < 410881L){...}

এই এক কোড:

if (n < 11043908100L) {
    //John Carmack hack, converted to Java.
    // See: http://www.codemaestro.com/reviews/9
    int i;
    float x2, y;

    x2 = n * 0.5F;
    y = n;
    i = Float.floatToRawIntBits(y);
    //using the magic number from 
    //http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf
    //since it more accurate
    i = 0x5f375a86 - (i >> 1);
    y = Float.intBitsToFloat(i);
    y = y * (1.5F - (x2 * y * y));
    y = y * (1.5F - (x2 * y * y)); //Newton iteration, more accurate

    sqrt = Math.round(1.0F / y);
} else {
    //Carmack hack gives incorrect answer for n >= 11043908100.
    sqrt = (long) Math.sqrt(n);
}

6

সাধারণ বিটের দৈর্ঘ্যের জন্য বিবেচনা করে (যদিও আমি এখানে নির্দিষ্ট ধরণের ব্যবহার করেছি), আমি নীচের মতো সরল আলগো ডিজাইনের চেষ্টা করেছি। 0,1,2 বা <0 এর জন্য সহজ এবং সুস্পষ্ট চেক প্রাথমিকভাবে প্রয়োজন। নিম্নলিখিতটি বোঝার পক্ষে সহজ যে এটি কোনও বিদ্যমান গণিতের ফাংশন ব্যবহার করার চেষ্টা করে না। বেশিরভাগ অপারেটর বিট-ওয়াইজ অপারেটরগুলির সাথে প্রতিস্থাপন করা যেতে পারে। যদিও আমি কোনও বেঞ্চ চিহ্নের ডেটা দিয়ে পরীক্ষা করি নি। আমি বিশেষত গণিত বা কম্পিউটার অ্যালগরিদম ডিজাইনের বিশেষজ্ঞ নই, আমি আপনাকে সমস্যাটি নির্দেশ করে দেখতে চাই। আমি জানি সেখানে উন্নতির প্রচুর সম্ভাবনা রয়েছে।

int main()
{
    unsigned int c1=0 ,c2 = 0;  
    unsigned int x = 0;  
    unsigned int p = 0;  
    int k1 = 0;  
    scanf("%d",&p);  
    if(p % 2 == 0) {  
        x = p/2; 
    }  
    else {  
        x = (p/2) +1;  
    }  
    while(x) 
    {
        if((x*x) > p) {  
            c1 = x;  
            x = x/2; 
        }else {  
            c2 = x;  
            break;  
        }  
    }  
    if((p%2) != 0)  
        c2++;

    while(c2 < c1) 
    {  
        if((c2 * c2 ) == p) {  
            k1 = 1;  
            break;  
        }  
        c2++; 
    }  
    if(k1)  
        printf("\n Perfect square for %d", c2);  
    else  
        printf("\n Not perfect but nearest to :%d :", c2);  
    return 0;  
}  

@ কিপ: আমার ব্রাউজারে কিছু সমস্যা।
নবম সারবাং

1
আপনার কিছু ইনডেন্টিং দরকার।
স্টিভ কুও

5

যখন কোনও বর্গক্ষেত্রের শেষ এন বিটগুলি পর্যবেক্ষণ করা হয় তখন আমি সমস্ত সম্ভাব্য ফলাফলগুলি পরীক্ষা করেছিলাম। ধারাবাহিকভাবে আরও বিট পরীক্ষা করে, 5/6 অবধি ইনপুটগুলি বাদ দেওয়া যায়। আমি আসলে এটি ফার্মেটের ফ্যাক্টরাইজেশন অ্যালগরিদম বাস্তবায়নের জন্য ডিজাইন করেছি এবং এটি খুব দ্রুত is

public static boolean isSquare(final long val) {
   if ((val & 2) == 2 || (val & 7) == 5) {
     return false;
   }
   if ((val & 11) == 8 || (val & 31) == 20) {
     return false;
   }

   if ((val & 47) == 32 || (val & 127) == 80) {
     return false;
   }

   if ((val & 191) == 128 || (val & 511) == 320) {
     return false;
   }

   // if((val & a == b) || (val & c == d){
   //   return false;
   // }

   if (!modSq[(int) (val % modSq.length)]) {
        return false;
   }

   final long root = (long) Math.sqrt(val);
   return root * root == val;
}

সিউডোকোডের শেষ বিটটি আরও মানগুলি নির্মূল করতে পরীক্ষাগুলি প্রসারিত করতে ব্যবহার করা যেতে পারে। উপরের পরীক্ষাগুলি কে = 0, 1, 2, 3 এর জন্য

  • এ রূপটির (3 << 2 কে) - 1
  • বি রূপের (2 << 2 কে)
  • সি ফর্মের (2 << 2 কে + 2) - 1
  • d ফর্মের (2 << 2 কে - 1) * 10

    এটি প্রথমে দুটি স্কোরের মডুলির সাথে বর্গক্ষেত্রের অবশিষ্টাংশ রয়েছে কিনা তা পরীক্ষা করে, তারপরে এটি একটি চূড়ান্ত মডিউলাসের উপর ভিত্তি করে পরীক্ষা করে, তারপরে এটি চূড়ান্ত পরীক্ষা করার জন্য ম্যাথ.এসকিআরটি ব্যবহার করে। আমি শীর্ষ পোস্ট থেকে ধারণাটি নিয়ে এসেছি এবং এটির উপরে প্রসারিত করার চেষ্টা করেছি। আমি কোন মন্তব্য বা পরামর্শ প্রশংসা করি।

    আপডেট: একটি মডুলাস, (ModSq) এবং 44352 এর একটি মডুলাস বেস দ্বারা পরীক্ষাটি ব্যবহার করে, আমার পরীক্ষাটি ওপি-র আপডেটে এক হাজারেরও বেশি পর্যন্ত সংখ্যাগুলির 96% সময়ের মধ্যে চলে।


  • 2

    এখানে একটি বিভাজন এবং বিজয় সমাধান।

    যদি কোনও প্রাকৃতিক সংখ্যা ( number) এর বর্গমূল একটি প্রাকৃতিক সংখ্যা ( ) হয় solution, তবে আপনি সহজেই solutionএর সংখ্যার সংখ্যার ভিত্তিতে একটি ব্যাপ্তি নির্ধারণ করতে পারেন number:

    • numberএর 1 ডিজিট রয়েছে: solutionপরিসীমা = 1 - 4
    • number2 টি সংখ্যা রয়েছে: solutionপরিসীমা = 3 - 10 এ
    • number3 টি সংখ্যা রয়েছে: solutionপরিসীমা = 10 - 40
    • number4 টি সংখ্যা রয়েছে: solutionপরিসীমা = 30 - 100
    • number5 টি সংখ্যা রয়েছে: solutionপরিসীমা = 100 - 400

    পুনরাবৃত্তি লক্ষ্য করুন?

    আপনি এই পরিসীমাটি বাইনারি অনুসন্ধানের পদ্ধতিতে ব্যবহার করতে পারেন তা দেখার solutionজন্য যে এখানে কোনটি রয়েছে:

    number == solution * solution

    কোডটি এখানে

    এখানে আমার ক্লাস স্কয়াররুটচেকার

    public class SquareRootChecker {
    
        private long number;
        private long initialLow;
        private long initialHigh;
    
        public SquareRootChecker(long number) {
            this.number = number;
    
            initialLow = 1;
            initialHigh = 4;
            if (Long.toString(number).length() % 2 == 0) {
                initialLow = 3;
                initialHigh = 10;
            }
            for (long i = 0; i < Long.toString(number).length() / 2; i++) {
                initialLow *= 10;
                initialHigh *= 10;
            }
            if (Long.toString(number).length() % 2 == 0) {
                initialLow /= 10;
                initialHigh /=10;
            }
        }
    
        public boolean checkSquareRoot() {
            return findSquareRoot(initialLow, initialHigh, number);
        }
    
        private boolean findSquareRoot(long low, long high, long number) {
            long check = low + (high - low) / 2;
            if (high >= low) {
                if (number == check * check) {
                    return true;
                }
                else if (number < check * check) {
                    high = check - 1;
                    return findSquareRoot(low, high, number);
                }
                else  {
                    low = check + 1;
                    return findSquareRoot(low, high, number);
                }
            }
            return false;
        }
    
    }

    এবং এটি কীভাবে ব্যবহার করতে হয় তার একটি উদাহরণ এখানে।

    long number =  1234567;
    long square = number * number;
    SquareRootChecker squareRootChecker = new SquareRootChecker(square);
    System.out.println(square + ": " + squareRootChecker.checkSquareRoot()); //Prints "1524155677489: true"
    
    long notSquare = square + 1;
    squareRootChecker = new SquareRootChecker(notSquare);
    System.out.println(notSquare + ": " + squareRootChecker.checkSquareRoot()); //Prints "1524155677490: false"

    2
    আমি ধারণাটি পছন্দ করি তবে আমি বিনয়ের সাথে একটি বড় ত্রুটিটি উল্লেখ করতে চাই: সংখ্যাগুলি বেস 2 বাইনারে রয়েছে। বেস 2 কে বেস 10 এ রূপান্তর toStringকরা বিটওয়াইজ অপারেটরগুলির তুলনায় অবিশ্বাস্যরূপে ব্যয়বহুল অপারেশন। সুতরাং, - কার্যকারিতা - প্রশ্নের উদ্দেশ্য পূরণে আপনাকে বেস 10 স্ট্রিংয়ের পরিবর্তে বিটওয়াইস অপারেটর ব্যবহার করতে হবে। আবার, আমি আপনার ধারণাটি সত্যিই পছন্দ করি। তবুও, আপনার বাস্তবায়ন (এটি এখন যেমন দাঁড়িয়েছে) প্রশ্নের পক্ষে পোস্ট করা সমস্ত সম্ভাব্য সমাধানগুলির মধ্যে এখন পর্যন্ত সবচেয়ে ধীরতম।
    জ্যাক গিফিন

    1

    গতি যদি উদ্বেগের বিষয় হয়ে থাকে তবে সর্বাধিক ব্যবহৃত উপকরণগুলির সেট এবং তাদের মানগুলি কোনও অনুসন্ধানের টেবিলে ভাগ না করে এবং তারপরে ব্যতিক্রমী মামলার জন্য আপনি যেই অনুকূলিত যাদু অ্যালগরিদম নিয়ে এসেছেন তা কেন করবেন না?


    সমস্যাটি হ'ল কোনও "ইনপুটগুলির সাধারণত ব্যবহৃত সেট" নেই - সাধারণত আমি কোনও তালিকার মাধ্যমে পুনরাবৃত্তি করি, তাই আমি একই ইনপুটগুলি দু'বার ব্যবহার করব না।
    কিপ

    1

    এটির চেয়ে আরও দক্ষতার সাথে 'শেষ এক্সের অঙ্কগুলি N হলে' একটি নিখুঁত বর্গক্ষেত্র হতে পারে না তা প্যাক করা উচিত! আমি জাভা 32 বিট ইনট ব্যবহার করব এবং সংখ্যাটির শেষ 16 টি বিট পরীক্ষা করতে পর্যাপ্ত ডেটা তৈরি করব - এটি 2048 হেক্সাডেসিমাল ইন-মান values

    ...

    ঠিক আছে. হয় আমি কিছু সংখ্যক তত্ত্ব নিয়ে চলেছি যা আমার থেকে কিছুটা দূরে, অথবা আমার কোডে একটি বাগ রয়েছে। যাইহোক, কোড এখানে:

    public static void main(String[] args) {
        final int BITS = 16;
    
        BitSet foo = new BitSet();
    
        for(int i = 0; i< (1<<BITS); i++) {
            int sq = (i*i);
            sq = sq & ((1<<BITS)-1);
            foo.set(sq);
        }
    
        System.out.println("int[] mayBeASquare = {");
    
        for(int i = 0; i< 1<<(BITS-5); i++) {
            int kk = 0;
            for(int j = 0; j<32; j++) {
                if(foo.get((i << 5) | j)) {
                    kk |= 1<<j;
                }
            }
            System.out.print("0x" + Integer.toHexString(kk) + ", ");
            if(i%8 == 7) System.out.println();
        }
        System.out.println("};");
    }

    এবং ফলাফল এখানে:

    (সম্পাদনা: প্রিটিফাই.জেজেজে দুর্বল পারফরম্যান্সের জন্য প্রযোজ্য; দেখতে পুনর্বিবেচনার ইতিহাস দেখুন))


    1

    পূর্ণসংখ্যার গাণিতিক সহ নিউটনের পদ্ধতি

    আপনি যদি অ-পূর্ণসংখ্যা অপারেশন এড়াতে চান তবে নীচের পদ্ধতিটি ব্যবহার করতে পারেন। এটি মূলত পূর্ণসংখ্যার গাণিতিকের জন্য সংশোধিত নিউটনের পদ্ধতিটি ব্যবহার করে।

    /**
     * Test if the given number is a perfect square.
     * @param n Must be greater than 0 and less
     *    than Long.MAX_VALUE.
     * @return <code>true</code> if n is a perfect
     *    square, or <code>false</code> otherwise.
     */
    public static boolean isSquare(long n)
    {
        long x1 = n;
        long x2 = 1L;
    
        while (x1 > x2)
        {
            x1 = (x1 + x2) / 2L;
            x2 = n / x1;
        }
    
        return x1 == x2 && n % x1 == 0L;
    }

    এই প্রয়োগটি যে সমাধানগুলি ব্যবহার করে তাতে প্রতিযোগিতা করতে পারে না Math.sqrt। যাইহোক, অন্যান্য কিছু পোস্টে বর্ণিত ফিল্টারিং মেকানিজম ব্যবহার করে এর কার্যকারিতা উন্নত করা যেতে পারে।


    1

    নিউটনের পদ্ধতি দ্বারা বর্গমূলের গণনা করা ভয়াবহভাবে দ্রুত ... তবে শুরুর মানটি যুক্তিসঙ্গত হয়। তবে এখানে কোনও যুক্তিসঙ্গত প্রারম্ভিক মান নেই এবং অনুশীলনে আমরা বাইসেকশন এবং লগ (2 ^ 64) আচরণ দিয়ে শেষ করি।
    সত্যই দ্রুত হতে আমাদের যুক্তিসঙ্গত প্রারম্ভিক মানটি পেতে একটি দ্রুত উপায় প্রয়োজন এবং এর অর্থ আমাদের মেশিনের ভাষায় নামতে হবে। যদি কোনও প্রসেসর পেন্টিয়ামে পিওপিসিএনটির মতো কোনও নির্দেশনা সরবরাহ করে, তবে নেতৃস্থানীয় শূন্যদের গণনা করা হয় আমরা এটির অর্ধেক উল্লেখযোগ্য বিট সহ প্রারম্ভিক মান পেতে ব্যবহার করতে পারি। যত্ন সহকারে আমরা নিউ নিউটনের পদক্ষেপগুলির একটি নির্দিষ্ট সংখ্যক সন্ধান করতে পারি যা সর্বদা যথেষ্ট। (এইভাবে লুপ করা দরকার এবং খুব দ্রুত সম্পাদন করা দরকার))

    দ্বিতীয় সমাধানটি ভাসমান পয়েন্ট সুবিধার মধ্য দিয়ে যাচ্ছে, যার মধ্যে একটি দ্রুত স্কয়ার্ট গণনা (আই ৮87 কোপ্রোসেসরের মতো থাকতে পারে) এক্সপ () এবং লগ () এর মাধ্যমে একটি ভ্রমণও বাইনারি অনুসন্ধানে নিউটনের অধঃপতিত হতে আরও দ্রুত হতে পারে। এটির একটি কৌতূহলীয় দিক রয়েছে, প্রসেসর নির্ভর বিশ্লেষণ কী এবং যদি পরে পরিশোধন করা আবশ্যক হয়।

    তৃতীয় সমাধানটি কিছুটা পৃথক সমস্যা সমাধান করে তবে এটি উল্লেখ করা ভাল কারণ পরিস্থিতিটি প্রশ্নে বর্ণিত হয়েছে। যদি আপনি সংখ্যার জন্য কিছুটা পৃথক সংখ্যার জন্য অনেকগুলি বর্গক্ষেত্রের শিকড় গণনা করতে চান তবে আপনি নিউটন পুনরাবৃত্তিটি ব্যবহার করতে পারেন, যদি আপনি আরম্ভের মানটি পুনরায় পুনর্নির্মাণ করেন না, তবে পূর্ববর্তী গণনাটি যেখানে রেখেছিলেন সেখানে কেবল এটি রেখে যান। আমি এটি কমপক্ষে একটি ইউলারের সমস্যায় সাফল্যের সাথে ব্যবহার করেছি।


    একটি ভাল অনুমান করা খুব কঠিন নয়। সমাধানের জন্য নিম্ন এবং উপরের সীমাটি অনুমান করতে আপনি সংখ্যার অঙ্কের সংখ্যাটি ব্যবহার করতে পারেন। আমার উত্তরও দেখুন যেখানে আমি একটি বিভাজন এবং বিজয়ী সমাধানের প্রস্তাব দিই।
    এমডব্লুবি

    পিওপিসিএনটি এবং অঙ্কের সংখ্যা গণনার মধ্যে পার্থক্য কী? আপনি এক ন্যানোসেকেন্ডে পিওপিসিএনটি করতে পারেন তা বাদ দিয়ে।
    অ্যালবার্ট ভ্যান ডার হর্স্ট

    1

    একটি সংখ্যার স্কোয়ার রুট, প্রদত্ত সংখ্যাটি নিখুঁত বর্গক্ষেত্র।

    জটিলতা হ'ল লগ (এন)

    /**
     * Calculate square root if the given number is a perfect square.
     * 
     * Approach: Sum of n odd numbers is equals to the square root of n*n, given 
     * that n is a perfect square.
     *
     * @param number
     * @return squareRoot
     */
    
    public static int calculateSquareRoot(int number) {
    
        int sum=1;
        int count =1;
        int squareRoot=1;
        while(sum<number) {
            count+=2;
            sum+=count;
            squareRoot++;
        }
        return squareRoot;
    }

    0

    যদি আপনি গতি চান, আপনার পূর্ণসংখ্যাগুলি সীমাবদ্ধ আকারের হয় তবে আমার সন্দেহ হয় যে দ্রুততম উপায়টি (ক) আকার দ্বারা পরামিতিগুলি বিভক্ত করতে হবে (উদাহরণস্বরূপ বৃহত্তম বিট সেট দ্বারা বিভাগগুলিতে), তারপরে নিখুঁত স্কোয়ারগুলির অ্যারের বিপরীতে মানটি পরীক্ষা করে যে সীমা মধ্যে।


    2
    দীর্ঘ পরিসরে 2 ^ 32 নিখুঁত স্কোয়ার রয়েছে। এই টেবিলটি বিশাল হবে। এছাড়াও, কোনও মেমরি অ্যাক্সেসের চেয়ে মান গণনা করার সুবিধাটি বিশাল হতে পারে।
    পিটারআলেন ওয়েলব

    ওহ না, নেই 2, 16 আছে। 2 ^ 32 হল 2 ^ 16 স্কোয়ার। 2 ^ 16 আছে।
    সেলেস্টিয়াল এম ওয়েইসেল

    3
    হ্যাঁ, তবে একটি দীর্ঘ পরিসীমা 32 বিট নয়, 64 বিট। বর্গমূল (2 ^ 64) = 2 ^ 32। (আমি গণিতকে কিছুটা সহজ করার জন্য সাইন বিটটি উপেক্ষা করছি ... আসলে (দীর্ঘ) (2 ^ 31.5) = 3037000499 নিখুঁত স্কোয়ার রয়েছে)
    কিপ

    0

    কারম্যাক পদ্ধতিটি সম্পর্কে, মনে হচ্ছে ঠিক একবারে পুনরাবৃত্তি করা বেশ সহজ হবে, যা সঠিকতার অঙ্কের সংখ্যা দ্বিগুণ করা উচিত। এটি সর্বোপরি, একটি খুব কাটা পুনরাবৃত্তি পদ্ধতি - খুব ভাল প্রথম অনুমান সহ নিউটনের।

    আপনার বর্তমান সেরা সম্পর্কে, আমি দুটি মাইক্রো-অপ্টিমাইজেশন দেখছি:

    • মোড 255 ব্যবহার করে চেকের পরে 0 টি বনাম 0 সরান
    • স্বাভাবিকের (75%) কেসগুলির জন্য সমস্ত চেক এড়িয়ে যাওয়ার জন্য চারটি বিভাজনকারী শক্তিকে পুনর্বিন্যাস করুন।

    অর্থাৎ,

    // Divide out powers of 4 using binary search
    
    if((n & 0x3L) == 0) {
      n >>=2;
    
      if((n & 0xffffffffL) == 0)
        n >>= 32;
      if((n & 0xffffL) == 0)
          n >>= 16;
      if((n & 0xffL) == 0)
          n >>= 8;
      if((n & 0xfL) == 0)
          n >>= 4;
      if((n & 0x3L) == 0)
          n >>= 2;
    }

    এমনকি আরও ভাল একটি সহজ হতে পারে

    while ((n & 0x03L) == 0) n >>= 2;

    স্পষ্টতই, প্রতিটি চেকপয়েন্টে কত সংখ্যক সংখ্যা জড়িত তা জেনে রাখা আকর্ষণীয় হবে - আমি বরং সন্দেহ করি যে চেকগুলি সত্যই স্বাধীন, যা জিনিসকে জটিল করে তোলে।

    আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
    Licensed under cc by-sa 3.0 with attribution required.