18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 Davidlohr Bueso <davidlohr.bueso@hp.com> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Based on the shift-and-subtract algorithm for computing integer 68c2ecf20Sopenharmony_ci * square root from Guy L. Steele. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/export.h> 118c2ecf20Sopenharmony_ci#include <linux/bitops.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/** 148c2ecf20Sopenharmony_ci * int_sqrt - computes the integer square root 158c2ecf20Sopenharmony_ci * @x: integer of which to calculate the sqrt 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Computes: floor(sqrt(x)) 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ciunsigned long int_sqrt(unsigned long x) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci unsigned long b, m, y = 0; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci if (x <= 1) 248c2ecf20Sopenharmony_ci return x; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci m = 1UL << (__fls(x) & ~1UL); 278c2ecf20Sopenharmony_ci while (m != 0) { 288c2ecf20Sopenharmony_ci b = y + m; 298c2ecf20Sopenharmony_ci y >>= 1; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (x >= b) { 328c2ecf20Sopenharmony_ci x -= b; 338c2ecf20Sopenharmony_ci y += m; 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci m >>= 2; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return y; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(int_sqrt); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#if BITS_PER_LONG < 64 438c2ecf20Sopenharmony_ci/** 448c2ecf20Sopenharmony_ci * int_sqrt64 - strongly typed int_sqrt function when minimum 64 bit input 458c2ecf20Sopenharmony_ci * is expected. 468c2ecf20Sopenharmony_ci * @x: 64bit integer of which to calculate the sqrt 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ciu32 int_sqrt64(u64 x) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci u64 b, m, y = 0; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (x <= ULONG_MAX) 538c2ecf20Sopenharmony_ci return int_sqrt((unsigned long) x); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci m = 1ULL << ((fls64(x) - 1) & ~1ULL); 568c2ecf20Sopenharmony_ci while (m != 0) { 578c2ecf20Sopenharmony_ci b = y + m; 588c2ecf20Sopenharmony_ci y >>= 1; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (x >= b) { 618c2ecf20Sopenharmony_ci x -= b; 628c2ecf20Sopenharmony_ci y += m; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci m >>= 2; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return y; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(int_sqrt64); 708c2ecf20Sopenharmony_ci#endif 71