Test integerness: Difference between revisions
Content added Content deleted
(→{{header|Ruby}}: Use simpler syntax on last example) |
(Add Go solution) |
||
Line 5: | Line 5: | ||
To be clear, we're not talking about whether the number is stored with the specific data type for integers, but instead we want to test whether there exists an integer with the exact same value. In other words, we want to test for integerness in the mathematical sense, not as a data type. |
To be clear, we're not talking about whether the number is stored with the specific data type for integers, but instead we want to test whether there exists an integer with the exact same value. In other words, we want to test for integerness in the mathematical sense, not as a data type. |
||
=={{header|Go}}== |
|||
<lang go>package main |
|||
import ( |
|||
"fmt" |
|||
"math" |
|||
"math/big" |
|||
"reflect" |
|||
"strings" |
|||
"unsafe" |
|||
) |
|||
func FloatIsInt(f float64) bool { return f == math.Trunc(f) } |
|||
func ComplexIsInt(c complex128) bool { return imag(c) == 0 && FloatIsInt(real(c)) } |
|||
// Usually just the above two would be all that is used, but if it is |
|||
// desired to have a single function that can test any arbitrary type, |
|||
// including the standard math/big types, user defined types based on an |
|||
// integer, float, or complex builtin types, or user defined types that |
|||
// have an IsInt() method, then reflection can be used. |
|||
type hasIsInt interface { |
|||
IsInt() bool |
|||
} |
|||
var bigIntT = reflect.TypeOf((*big.Int)(nil)) |
|||
func IsInt(i interface{}) bool { |
|||
if ci, ok := i.(hasIsInt); ok { |
|||
// Handles things like *big.Rat |
|||
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: |
|||
// Built-in types and any custom type based on them |
|||
return true |
|||
case reflect.Float32, reflect.Float64: |
|||
// Built-in floats and anything based on them |
|||
return FloatIsInt(v.Float()) |
|||
case reflect.Complex64, reflect.Complex128: |
|||
// Built-in complexes and anything based on them |
|||
return ComplexIsInt(v.Complex()) |
|||
case reflect.String: |
|||
// Could also do strconv.ParseFloat then FloatIsInt but |
|||
// big.Rat handles everything ParseFloat can plus more. |
|||
// Note, there is no strconv.ParseComplex. |
|||
if r, ok := new(big.Rat).SetString(v.String()); ok { |
|||
return r.IsInt() |
|||
} |
|||
case reflect.Ptr: |
|||
// Special case for math/big.Int |
|||
if v.Type() == bigIntT { |
|||
return true |
|||
} |
|||
} |
|||
return false |
|||
} |
|||
// The rest is just demonstration and display |
|||
type intbased int16 |
|||
type complexbased complex64 |
|||
type customIntegerType struct { |
|||
// Anything that stores or represents a sub-set |
|||
// of integer values in any way desired. |
|||
} |
|||
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 FloatIsInt with float64:\n", hdr) |
|||
for _, f := range []float64{ |
|||
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(FloatIsInt(f), f) |
|||
} |
|||
fmt.Print("\nUsing ComplexIsInt with complex128:\n", hdr) |
|||
for _, c := range []complex128{ |
|||
3, 1i, 0i, 3.4, |
|||
} { |
|||
show2(ComplexIsInt(c), c) |
|||
} |
|||
fmt.Println("\nUsing reflection:") |
|||
fmt.Print(hdr) |
|||
show("hello") |
|||
show(math.MaxFloat64) |
|||
show("9e100") |
|||
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).SetString("2/3") |
|||
show(r) |
|||
r.SetFrac(b, new(big.Int).SetInt64(9)) |
|||
show(r) |
|||
show("12345/5") |
|||
show(new(customIntegerType)) |
|||
}</lang> |
|||
{{out}} |
|||
<pre> |
|||
Using FloatIsInt with float64: |
|||
Input IsInt Type |
|||
0 true float64 |
|||
-2 true float64 |
|||
-2.000000000000001 false float64 |
|||
5 true float64 |
|||
7.333333333333333 false float64 |
|||
3.141592653589793 false float64 |
|||
-9.223372036854776e+18 true float64 |
|||
1.8446744073709552e+19 true float64 |
|||
5e-324 false float64 |
|||
1.7976931348623157e+308 true float64 |
|||
NaN false float64 |
|||
+Inf true float64 |
|||
-Inf true float64 |
|||
Using ComplexIsInt with complex128: |
|||
Input IsInt Type |
|||
(3+0i) true complex128 |
|||
(0+1i) false complex128 |
|||
(0+0i) true complex128 |
|||
(3.4+0i) false complex128 |
|||
Using reflection: |
|||
Input IsInt Type |
|||
hello false string |
|||
1.7976931348623157e+308 true float64 |
|||
9e100 true string |
|||
(4+0i) false string (complex strings not parsed) |
|||
(4+0i) true complex128 |
|||
167 true int32 or rune |
|||
65 true uint8 or byte |
|||
5200 true main.intbased |
|||
(5+0i) true main.complexbased |
|||
(5+1i) false main.complexbased |
|||
34367302872 true uintptr |
|||
-2147483648 true int |
|||
18446744073709551615 true uint64 |
|||
9999999999999999999999999 true *big.Int |
|||
2/3 false *big.Rat |
|||
1111111111111111111111111/1 true *big.Rat |
|||
12345/5 true string |
|||
<…> true *main.customIntegerType |
|||
</pre> |
|||
=={{header|J}}== |
=={{header|J}}== |