Task: Test integerness


C++: #include <complex>
#include <math.h>
#include <iostream>

template<class Type>
struct Precision
{
public:
	static Type GetEps()
	{
		return eps;
	}

	static void SetEps(Type e)
	{
		eps = e;
	}

private:
	static Type eps;
};

template<class Type> Type Precision<Type>::eps = static_cast<Type>(1E-7);

template<class DigType>
bool IsDoubleEqual(DigType d1, DigType d2)
{
	return (fabs(d1 - d2) < Precision<DigType>::GetEps());
}

template<class DigType>
DigType IntegerPart(DigType value)
{
	return (value > 0) ? floor(value) : ceil(value);
}

template<class DigType>
DigType FractionPart(DigType value)
{
	return fabs(IntegerPart<DigType>(value) - value);
}

template<class Type>
bool IsInteger(const Type& value)
{
	return false;
}

#define GEN_CHECK_INTEGER(type)			\
template<>					\
bool IsInteger<type>(const type& value)         \
{						\
	return true;				\
}

#define GEN_CHECK_CMPL_INTEGER(type)					\
template<>								\
bool IsInteger<std::complex<type> >(const std::complex<type>& value)	\
{									\
	type zero = type();						\
	return value.imag() == zero;					\
}

#define GEN_CHECK_REAL(type)						\
template<>								\
bool IsInteger<type>(const type& value)					\
{									\
	type zero = type();						\
	return IsDoubleEqual<type>(FractionPart<type>(value), zero);	\
}

#define GEN_CHECK_CMPL_REAL(type)					\
template<>								\
bool IsInteger<std::complex<type> >(const std::complex<type>& value)	\
{									\
	type zero = type();						\
	return IsDoubleEqual<type>(value.imag(), zero);			\
}

#define GEN_INTEGER(type)		\
	GEN_CHECK_INTEGER(type)		\
	GEN_CHECK_CMPL_INTEGER(type)

#define GEN_REAL(type)			\
	GEN_CHECK_REAL(type)		\
	GEN_CHECK_CMPL_REAL(type)


GEN_INTEGER(char)
GEN_INTEGER(unsigned char)
GEN_INTEGER(short)
GEN_INTEGER(unsigned short)
GEN_INTEGER(int)
GEN_INTEGER(unsigned int)
GEN_INTEGER(long)
GEN_INTEGER(unsigned long)
GEN_INTEGER(long long)
GEN_INTEGER(unsigned long long)

GEN_REAL(float)
GEN_REAL(double)
GEN_REAL(long double)

template<class Type>
inline void TestValue(const Type& value)
{
	std::cout << "Value: " << value << " of type: " << typeid(Type).name() << " is integer - " << std::boolalpha << IsInteger(value) << std::endl;
}

int main()
{
	char c = -100;
	unsigned char uc = 200;
	short s = c;
	unsigned short us = uc;
	int i = s;
	unsigned int ui = us;
	long long ll = i;
	unsigned long long ull = ui;

	std::complex<unsigned int> ci1(2, 0);
	std::complex<int> ci2(2, 4);
	std::complex<int> ci3(-2, 4);
	std::complex<unsigned short> cs1(2, 0);
	std::complex<short> cs2(2, 4);
	std::complex<short> cs3(-2, 4);

	std::complex<double> cd1(2, 0);
	std::complex<float> cf1(2, 4);
	std::complex<double> cd2(-2, 4);

	float f1 = 1.0;
	float f2 = -2.0;
	float f3 = -2.4f;
	float f4 = 1.23e-5f;
	float f5 = 1.23e-10f;
	double d1 = f5;

	TestValue(c);
	TestValue(uc);
	TestValue(s);
	TestValue(us);
	TestValue(i);
	TestValue(ui);
	TestValue(ll);
	TestValue(ull);

	TestValue(ci1);
	TestValue(ci2);
	TestValue(ci3);
	TestValue(cs1);
	TestValue(cs2);
	TestValue(cs3);

	TestValue(cd1);
	TestValue(cd2);
	TestValue(cf1);

	TestValue(f1);
	TestValue(f2);
	TestValue(f3);
	TestValue(f4);
	TestValue(f5);
	std::cout << "Set float precision: 1e-15f\n";
	Precision<float>::SetEps(1e-15f);
	TestValue(f5);
	TestValue(d1);
	return 0;
}



Go: package main

import (
	"fmt"
	"math"
	"math/big"
	"reflect"
	"strings"
	"unsafe"
)







func Float64IsInt(f float64) bool {
	_, frac := math.Modf(f)
	return frac == 0
}




func Float32IsInt(f float32) bool {
	return Float64IsInt(float64(f))
}

func Complex128IsInt(c complex128) bool {
	return imag(c) == 0 && Float64IsInt(real(c))
}

func Complex64IsInt(c complex64) bool {
	return imag(c) == 0 && Float64IsInt(float64(real(c)))
}







type hasIsInt interface {
	IsInt() bool
}

var bigIntT = reflect.TypeOf((*big.Int)(nil))

func IsInt(i interface{}) bool {
	if ci, ok := i.(hasIsInt); ok {
		
		return ci.IsInt()
	}
	switch v := reflect.ValueOf(i); v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16,
		reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16,
		reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		
		return true
	case reflect.Float32, reflect.Float64:
		
		return Float64IsInt(v.Float())
	case reflect.Complex64, reflect.Complex128:
		
		return Complex128IsInt(v.Complex())
	case reflect.String:
		
		
		
		if r, ok := new(big.Rat).SetString(v.String()); ok {
			return r.IsInt()
		}
	case reflect.Ptr:
		
		if v.Type() == bigIntT {
			return true
		}
	}
	return false
}



type intbased int16
type complexbased complex64
type customIntegerType struct {
	
	
}

func (customIntegerType) IsInt() bool    { return true }
func (customIntegerType) String() string { return "<…>" }

func main() {
	hdr := fmt.Sprintf("%27s  %-6s %s\n", "Input", "IsInt", "Type")
	show2 := func(t bool, i interface{}, args ...interface{}) {
		istr := fmt.Sprint(i)
		fmt.Printf("%27s  %-6t %T ", istr, t, i)
		fmt.Println(args...)
	}
	show := func(i interface{}, args ...interface{}) {
		show2(IsInt(i), i, args...)
	}

	fmt.Print("Using Float64IsInt with float64:\n", hdr)
	neg1 := -1.
	for _, f := range []float64{
		0, neg1 * 0, -2, -2.000000000000001, 10. / 2, 22. / 3,
		math.Pi,
		math.MinInt64, math.MaxUint64,
		math.SmallestNonzeroFloat64, math.MaxFloat64,
		math.NaN(), math.Inf(1), math.Inf(-1),
	} {
		show2(Float64IsInt(f), f)
	}

	fmt.Print("\nUsing Complex128IsInt with complex128:\n", hdr)
	for _, c := range []complex128{
		3, 1i, 0i, 3.4,
	} {
		show2(Complex128IsInt(c), c)
	}

	fmt.Println("\nUsing reflection:")
	fmt.Print(hdr)
	show("hello")
	show(math.MaxFloat64)
	show("9e100")
	f := new(big.Float)
	show(f)
	f.SetString("1e-3000")
	show(f)
	show("(4+0i)", "(complex strings not parsed)")
	show(4 + 0i)
	show(rune('§'), "or rune")
	show(byte('A'), "or byte")
	var t1 intbased = 5200
	var t2a, t2b complexbased = 5 + 0i, 5 + 1i
	show(t1)
	show(t2a)
	show(t2b)
	x := uintptr(unsafe.Pointer(&t2b))
	show(x)
	show(math.MinInt32)
	show(uint64(math.MaxUint64))
	b, _ := new(big.Int).SetString(strings.Repeat("9", 25), 0)
	show(b)
	r := new(big.Rat)
	show(r)
	r.SetString("2/3")
	show(r)
	show(r.SetFrac(b, new(big.Int).SetInt64(9)))
	show("12345/5")
	show(new(customIntegerType))
}