long fp_log10(long n, unsigned int fracbits) {
  long log2, frac;
  const long fp_one = (1 << fracbits);
  const long fp_two = (2 << fracbits);
  const long tolerance = (1 << ((fracbits / 2) + 2));
  if (n <= 0)
    return -(0x7fffffff);
  log2 = 0;
  while (n < fp_one) {
    log2 -= fp_one;
    n <<= 1;
  }
  while (n >= fp_two) {
    log2 += fp_one;
    n >>= 1;
  }
  frac = fp_one;
  while (frac > tolerance) {
    frac >>= 1;
    n = (long)((((long long)(n)) * ((long long)(n))) >> (fracbits));
    if (n >= fp_two) {
      n >>= 1;
      log2 += frac;
    }
  }
  return (long)((((long long)(log2)) *
                 ((long long)(((80807124L) >> (28 - fracbits))))) >>
                (fracbits));
}


x86 assembly (clang, -O0):
<fp_log10>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x10(%rbp)
mov    %esi,-0x14(%rbp)
mov    -0x14(%rbp),%ecx
mov    $0x1,%eax
shl    %cl,%eax
cltq
mov    %rax,-0x30(%rbp)
mov    -0x14(%rbp),%ecx
mov    $0x2,%eax
shl    %cl,%eax
cltq
mov    %rax,-0x38(%rbp)
mov    -0x14(%rbp),%ecx
shr    $0x1,%ecx
add    $0x2,%ecx
mov    $0x1,%eax
shl    %cl,%eax
cltq
mov    %rax,-0x40(%rbp)
cmpq   $0x0,-0x10(%rbp)
jg     1159 <fp_log10+0x59>
movq   $0xffffffff80000001,-0x8(%rbp)
80
jmp    1246 <fp_log10+0x146>
movq   $0x0,-0x20(%rbp)
mov    -0x10(%rbp),%rax
cmp    -0x30(%rbp),%rax
jge    118f <fp_log10+0x8f>
mov    -0x30(%rbp),%rcx
mov    -0x20(%rbp),%rax
sub    %rcx,%rax
mov    %rax,-0x20(%rbp)
mov    -0x10(%rbp),%rax
shl    $0x1,%rax
mov    %rax,-0x10(%rbp)
jmp    1161 <fp_log10+0x61>
jmp    1194 <fp_log10+0x94>
mov    -0x10(%rbp),%rax
cmp    -0x38(%rbp),%rax
jl     11bf <fp_log10+0xbf>
mov    -0x30(%rbp),%rax
add    -0x20(%rbp),%rax
mov    %rax,-0x20(%rbp)
mov    -0x10(%rbp),%rax
sar    $0x1,%rax
mov    %rax,-0x10(%rbp)
jmp    1194 <fp_log10+0x94>
mov    -0x30(%rbp),%rax
mov    %rax,-0x28(%rbp)
mov    -0x28(%rbp),%rax
cmp    -0x40(%rbp),%rax
jle    121f <fp_log10+0x11f>
mov    -0x28(%rbp),%rax
sar    $0x1,%rax
mov    %rax,-0x28(%rbp)
mov    -0x10(%rbp),%rax
imul   -0x10(%rbp),%rax
mov    -0x14(%rbp),%ecx
sar    %cl,%rax
mov    %rax,-0x10(%rbp)
mov    -0x10(%rbp),%rax
cmp    -0x38(%rbp),%rax
jl     121a <fp_log10+0x11a>
mov    -0x10(%rbp),%rax
sar    $0x1,%rax
mov    %rax,-0x10(%rbp)
mov    -0x28(%rbp),%rax
add    -0x20(%rbp),%rax
mov    %rax,-0x20(%rbp)
jmp    11c7 <fp_log10+0xc7>
mov    -0x20(%rbp),%rax
mov    $0x1c,%ecx
sub    -0x14(%rbp),%ecx
mov    %ecx,%ecx
mov    $0x4d104d4,%edx
sar    %cl,%rdx
mov    %rdx,%rcx
imul   %rcx,%rax
mov    -0x14(%rbp),%ecx
sar    %cl,%rax
mov    %rax,-0x8(%rbp)
mov    -0x8(%rbp),%rax
pop    %rbp
ret

x86 assembly (clang, -O2):
<fp_log10>:
mov    %esi,%r8d
mov    $0x1,%r10d
mov    %r8d,%ecx
shl    %cl,%r10d
mov    $0x2,%edx
shl    %cl,%edx
mov    %esi,%ecx
shr    %ecx
mov    $0x4,%r11d
shl    %cl,%r11d
test   %rdi,%rdi
jle    11b0 <fp_log10+0xb0>
push   %r14
push   %rbx
movslq %r10d,%rbx
movslq %edx,%r14
xor    %esi,%esi
cmp    %rdi,%rbx
jle    1156 <fp_log10+0x56>
nopl   0x0(%rax)
sub    %rbx,%rsi
add    %rdi,%rdi
cmp    %rbx,%rdi
jl     1140 <fp_log10+0x40>
jmp    1156 <fp_log10+0x56>
nopl   (%rax)
add    %rbx,%rsi
sar    %rdi
cmp    %r14,%rdi
jge    1150 <fp_log10+0x50>
mov    %r8d,%r9d
cmp    %r11d,%r10d
jle    1195 <fp_log10+0x95>
movslq %r11d,%rdx
xor    %r10d,%r10d
nopl   0x0(%rax)
sar    %rbx
imul   %rdi,%rdi
mov    %r9d,%ecx
shr    %cl,%rdi
cmp    %r14,%rdi
setge  %cl
mov    %rbx,%rax
cmovl  %r10,%rax
add    %rax,%rsi
sar    %cl,%rdi
cmp    %rdx,%rbx
jg     1170 <fp_log10+0x70>
mov    $0x1c,%cl
sub    %r8b,%cl
mov    $0x4d104d4,%eax
shr    %cl,%rax
imul   %rsi,%rax
mov    %r9d,%ecx
sar    %cl,%rax
pop    %rbx
pop    %r14
ret
mov    $0xffffffff80000001,%rax
ret

LLVM IR (-O0):
define i64 @fp_log10(i64 %0, i32 %1) {
%3 = alloca i64
%4 = alloca i64
%5 = alloca i32
%6 = alloca i64
%7 = alloca i64
%8 = alloca i64
%9 = alloca i64
%10 = alloca i64
store i64 %0, i64* %4
store i32 %1, i32* %5
%11 = load i32, i32* %5
%12 = shl i32 1, %11
%13 = sext i32 %12 to i64
store i64 %13, i64* %8
%14 = load i32, i32* %5
%15 = shl i32 2, %14
%16 = sext i32 %15 to i64
store i64 %16, i64* %9
%17 = load i32, i32* %5
%18 = udiv i32 %17, 2
%19 = add i32 %18, 2
%20 = shl i32 1, %19
%21 = sext i32 %20 to i64
store i64 %21, i64* %10
%22 = load i64, i64* %4
%23 = icmp sle i64 %22, 0
br i1 %23, label %24, label %25
24: ; preds = %2
store i64 -2147483647, i64* %3
br label %82
25: ; preds = %2
store i64 0, i64* %6
br label %26
26: ; preds = %30, %25
%27 = load i64, i64* %4
%28 = load i64, i64* %8
%29 = icmp slt i64 %27, %28
br i1 %29, label %30, label %36
30: ; preds = %26
%31 = load i64, i64* %8
%32 = load i64, i64* %6
%33 = sub nsw i64 %32, %31
store i64 %33, i64* %6
%34 = load i64, i64* %4
%35 = shl i64 %34, 1
store i64 %35, i64* %4
br label %26
36: ; preds = %26
br label %37
37: ; preds = %41, %36
%38 = load i64, i64* %4
%39 = load i64, i64* %9
%40 = icmp sge i64 %38, %39
br i1 %40, label %41, label %47
41: ; preds = %37
%42 = load i64, i64* %8
%43 = load i64, i64* %6
%44 = add nsw i64 %43, %42
store i64 %44, i64* %6
%45 = load i64, i64* %4
%46 = ashr i64 %45, 1
store i64 %46, i64* %4
br label %37
47: ; preds = %37
%48 = load i64, i64* %8
store i64 %48, i64* %7
br label %49
49: ; preds = %71, %47
%50 = load i64, i64* %7
%51 = load i64, i64* %10
%52 = icmp sgt i64 %50, %51
br i1 %52, label %53, label %72
53: ; preds = %49
%54 = load i64, i64* %7
%55 = ashr i64 %54, 1
store i64 %55, i64* %7
%56 = load i64, i64* %4
%57 = load i64, i64* %4
%58 = mul nsw i64 %56, %57
%59 = load i32, i32* %5
%60 = zext i32 %59 to i64
%61 = ashr i64 %58, %60
store i64 %61, i64* %4
%62 = load i64, i64* %4
%63 = load i64, i64* %9
%64 = icmp sge i64 %62, %63
br i1 %64, label %65, label %71
65: ; preds = %53
%66 = load i64, i64* %4
%67 = ashr i64 %66, 1
store i64 %67, i64* %4
%68 = load i64, i64* %7
%69 = load i64, i64* %6
%70 = add nsw i64 %69, %68
store i64 %70, i64* %6
br label %71
71: ; preds = %65, %53
br label %49
72: ; preds = %49
%73 = load i64, i64* %6
%74 = load i32, i32* %5
%75 = sub i32 28, %74
%76 = zext i32 %75 to i64
%77 = ashr i64 80807124, %76
%78 = mul nsw i64 %73, %77
%79 = load i32, i32* %5
%80 = zext i32 %79 to i64
%81 = ashr i64 %78, %80
store i64 %81, i64* %3
br label %82
82: ; preds = %72, %24
%83 = load i64, i64* %3
ret i64 %83
}

LLVM IR (-O2):
define i64 @fp_log10(i64 %0, i32 %1) {
%3 = shl nuw i32 1, %1
%4 = sext i32 %3 to i64
%5 = shl i32 2, %1
%6 = sext i32 %5 to i64
%7 = lshr i32 %1, 1
%8 = shl i32 4, %7
%9 = sext i32 %8 to i64
%10 = icmp slt i64 %0, 1
br i1 %10, label %55, label %11
11: ; preds = %2
%12 = icmp sgt i64 %4, %0
br i1 %12, label %17, label %13
13: ; preds = %17, %11
%14 = phi i64 [ 0, %11 ], [ %20, %17 ]
%15 = phi i64 [ %0, %11 ], [ %21, %17 ]
%16 = icmp slt i64 %15, %6
br i1 %16, label %23, label %28
17: ; preds = %11, %17
%18 = phi i64 [ %21, %17 ], [ %0, %11 ]
%19 = phi i64 [ %20, %17 ], [ 0, %11 ]
%20 = sub nsw i64 %19, %4
%21 = shl i64 %18, 1
%22 = icmp slt i64 %21, %4
br i1 %22, label %17, label %13
23: ; preds = %28, %13
%24 = phi i64 [ %14, %13 ], [ %31, %28 ]
%25 = phi i64 [ %15, %13 ], [ %32, %28 ]
%26 = icmp sgt i32 %3, %8
%27 = zext i32 %1 to i64
br i1 %26, label %34, label %48
28: ; preds = %13, %28
%29 = phi i64 [ %32, %28 ], [ %15, %13 ]
%30 = phi i64 [ %31, %28 ], [ %14, %13 ]
%31 = add nsw i64 %30, %4
%32 = ashr i64 %29, 1
%33 = icmp slt i64 %32, %6
br i1 %33, label %23, label %28
34: ; preds = %23, %34
%35 = phi i64 [ %46, %34 ], [ %25, %23 ]
%36 = phi i64 [ %43, %34 ], [ %24, %23 ]
%37 = phi i64 [ %38, %34 ], [ %4, %23 ]
%38 = ashr i64 %37, 1
%39 = mul nsw i64 %35, %35
%40 = lshr i64 %39, %27
%41 = icmp slt i64 %40, %6
%42 = select i1 %41, i64 0, i64 %38
%43 = add nsw i64 %42, %36
%44 = xor i1 %41, true
%45 = zext i1 %44 to i64
%46 = ashr i64 %40, %45
%47 = icmp sgt i64 %38, %9
br i1 %47, label %34, label %48
48: ; preds = %34, %23
%49 = phi i64 [ %24, %23 ], [ %43, %34 ]
%50 = sub i32 28, %1
%51 = zext i32 %50 to i64
%52 = lshr i64 80807124, %51
%53 = mul nsw i64 %49, %52
%54 = ashr i64 %53, %27
br label %55
55: ; preds = %2, %48
%56 = phi i64 [ %54, %48 ], [ -2147483647, %2 ]
ret i64 %56
}