#Rust, 275 bytes
Rust, 275 bytes
fn h(n:u32)->String{let i=[(30,"Gi"),(20,"Mi"),(10,"Ki"),(0,"")].iter().map(|x| (n as f32/2f32.powi(x.0),x.1)).filter(|y| y.0<999.5).last().unwrap();format!("{}{}B",if n<1000{format!("{}",n)}else{format!("{:.4}",format!("{:.2}",i.0)).trim_right_matches(".").to_string()},i.1)}
The basic idea is borrowed from the other answers, but formatting the string to have the proper number of significant digits, not have trailing decimal points, and not have numbers like 423.78 takes over half of the code... and it still rounds wrong (19.1 should be 19.2)