162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2013 Davidlohr Bueso <davidlohr.bueso@hp.com> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Based on the shift-and-subtract algorithm for computing integer 662306a36Sopenharmony_ci * square root from Guy L. Steele. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/export.h> 1062306a36Sopenharmony_ci#include <linux/bitops.h> 1162306a36Sopenharmony_ci#include <linux/limits.h> 1262306a36Sopenharmony_ci#include <linux/math.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/** 1562306a36Sopenharmony_ci * int_sqrt - computes the integer square root 1662306a36Sopenharmony_ci * @x: integer of which to calculate the sqrt 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Computes: floor(sqrt(x)) 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ciunsigned long int_sqrt(unsigned long x) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci unsigned long b, m, y = 0; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci if (x <= 1) 2562306a36Sopenharmony_ci return x; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci m = 1UL << (__fls(x) & ~1UL); 2862306a36Sopenharmony_ci while (m != 0) { 2962306a36Sopenharmony_ci b = y + m; 3062306a36Sopenharmony_ci y >>= 1; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (x >= b) { 3362306a36Sopenharmony_ci x -= b; 3462306a36Sopenharmony_ci y += m; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci m >>= 2; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci return y; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ciEXPORT_SYMBOL(int_sqrt); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#if BITS_PER_LONG < 64 4462306a36Sopenharmony_ci/** 4562306a36Sopenharmony_ci * int_sqrt64 - strongly typed int_sqrt function when minimum 64 bit input 4662306a36Sopenharmony_ci * is expected. 4762306a36Sopenharmony_ci * @x: 64bit integer of which to calculate the sqrt 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ciu32 int_sqrt64(u64 x) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci u64 b, m, y = 0; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (x <= ULONG_MAX) 5462306a36Sopenharmony_ci return int_sqrt((unsigned long) x); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci m = 1ULL << ((fls64(x) - 1) & ~1ULL); 5762306a36Sopenharmony_ci while (m != 0) { 5862306a36Sopenharmony_ci b = y + m; 5962306a36Sopenharmony_ci y >>= 1; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (x >= b) { 6262306a36Sopenharmony_ci x -= b; 6362306a36Sopenharmony_ci y += m; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci m >>= 2; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return y; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ciEXPORT_SYMBOL(int_sqrt64); 7162306a36Sopenharmony_ci#endif 72