I just use the dumb loop method because it's easy to read/understand, and determining the maximum mip-chain length is not done often enough to warrant micro-optimizing :)
Those floating-point operations are very expensive. You are generally better off doing manipulations with integers, although there are faster methods than your loop.
32 - __builtin_clz(max(height, width)); // gcc only; but I am sure other compilers have similar constructs
clz/ctz are called BitscanReverse/BitscanForward on MSVC, and yep, these intrinsics map to a nice single x86 instruction :)
However, that method doesnt work for counting mips of textures that arent a power of 2 (without some extra bit twiddling to detect that more bits than the MSB are set, and to add 1 to the result).