Converting statvfs to percentage free correctly

On your Edit #2, the Usage% calculation needs to be updated to this to match df output:

100.0 * (double) (vfs.f_blocks - vfs.f_bfree) / (double) (vfs.f_blocks - vfs.f_bfree + vfs.f_bavail)

Reasoning:
Used = f_blocks - f_bfree
Avail = f_bavail
df % = Used / (Used + Avail)


df's data may be based on f_bavail, not f_bfree. You may find it helpful to look at the source code to df to see how it does things. It has a number of edge cases it needs to deal with (eg, when the used space exceeds the amount of space available to non-root users), but the relevant code for the normal case is here:

  uintmax_t u100 = used * 100;
  uintmax_t nonroot_total = used + available;
  pct = u100 / nonroot_total + (u100 % nonroot_total != 0);

In other words, 100 * used / (used + available), rounded up. Plugging in the values from your df output gives 100 * 14159676 / (14159676 + 25837672) = 35.4015371, which rounded up is 36%, just as df calculated.