use crate::types::I32F32;
use crate::types::I256F256;

#[test]
fn you_can_add_numbers(){
	let a=I256F256::from((3i128*2).pow(4));
	assert_eq!(a+a,I256F256::from((3i128*2).pow(4)*2))
}

#[test]
fn you_can_shr_numbers(){
	let a=I32F32::from(4);
	assert_eq!(a>>1,I32F32::from(2))
}

#[test]
fn test_wide_mul(){
	let a=I32F32::ONE;
	let aa=a.wide_mul_1_1(a);
	assert_eq!(aa,crate::types::I64F64::ONE);
}

#[test]
fn test_wide_mul_repeated() {
	let a=I32F32::from(2);
	let b=I32F32::from(3);

	let w1=a.wide_mul_1_1(b);
	let w2=w1.wide_mul_2_2(w1);
	let w3=w2.wide_mul_4_4(w2);

	assert_eq!(w3,I256F256::from((3i128*2).pow(4)));
}

#[test]
fn test_bint(){
	let a=I32F32::ONE;
	assert_eq!(a*2,I32F32::from(2));
}

#[test]
fn test_sqrt(){
	let a=I32F32::ONE*4;
	assert_eq!(a.sqrt(),I32F32::from(2));
}
#[test]
fn test_sqrt_zero(){
	let a=I32F32::ZERO;
	assert_eq!(a.sqrt(),I32F32::ZERO);
}
#[test]
fn test_sqrt_low(){
	let a=I32F32::HALF;
	let b=a*a;
	assert_eq!(b.sqrt(),a);
}
fn find_equiv_sqrt_via_f64(n:I32F32)->I32F32{
	//GIMME THEM BITS BOY
	let &[bits]=n.to_bits().to_bits().digits();
	let ibits=bits as i64;
	let f=(ibits as f64)/((1u64<<32) as f64);
	let f_ans=f.sqrt();
	let i=(f_ans*((1u64<<32) as f64)) as i64;
	let r=I32F32::from_bits(bnum::BInt::<1>::from(i));
	//mimic the behaviour of the algorithm,
	//return the result if it truncates to the exact answer
	if (r+I32F32::EPSILON).wide_mul_1_1(r+I32F32::EPSILON)==n.wide_mul_1_1(I32F32::ONE){
		return r+I32F32::EPSILON;
	}
	if (r-I32F32::EPSILON).wide_mul_1_1(r-I32F32::EPSILON)==n.wide_mul_1_1(I32F32::ONE){
		return r-I32F32::EPSILON;
	}
	return r;
}
fn test_exact(n:I32F32){
	assert_eq!(n.sqrt(),find_equiv_sqrt_via_f64(n));
}
#[test]
fn test_sqrt_exact(){
	//43
	for i in 0..((i64::MAX as f32).ln() as u32){
		let n=I32F32::from_bits(bnum::BInt::<1>::from((i as f32).exp() as i64));
		test_exact(n);
	}
}
#[test]
fn test_sqrt_max(){
	let a=I32F32::MAX;
	test_exact(a);
}