{"action":"created","issue":{"url":"https://api.github.com/repos/lspector/Clojush/issues/170","labels_url":"https://api.github.com/repos/lspector/Clojush/issues/170/labels{/name}","comments_url":"https://api.github.com/repos/lspector/Clojush/issues/170/comments","events_url":"https://api.github.com/repos/lspector/Clojush/issues/170/events","html_url":"https://github.com/lspector/Clojush/issues/170","id":112251952,"number":170,"title":"Please formally specify numeric type handling rules","user":{"login":"Vaguery","id":81171,"avatar_url":"https://avatars.githubusercontent.com/u/81171?v=3","gravatar_id":"","url":"https://api.github.com/users/Vaguery","html_url":"https://github.com/Vaguery","followers_url":"https://api.github.com/users/Vaguery/followers","following_url":"https://api.github.com/users/Vaguery/following{/other_user}","gists_url":"https://api.github.com/users/Vaguery/gists{/gist_id}","starred_url":"https://api.github.com/users/Vaguery/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Vaguery/subscriptions","organizations_url":"https://api.github.com/users/Vaguery/orgs","repos_url":"https://api.github.com/users/Vaguery/repos","events_url":"https://api.github.com/users/Vaguery/events{/privacy}","received_events_url":"https://api.github.com/users/Vaguery/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-10-19T23:14:57Z","updated_at":"2015-10-20T01:08:19Z","closed_at":null,"body":"So I'm trying to write tests for the `Interpreter` \"routing\" system, which is the cascade of recognizers that send items on the `:exec` stack to the appropriate other stacks.\r\n\r\nAt the moment [this is the code that handles that](https://github.com/lspector/Clojush/blob/master/src/clojush/util.clj#L11-L22), but the behavior of particular programs and the results of calculations are also filtered through [this kind of ad hoc thingie](https://github.com/lspector/Clojush/blob/master/src/clojush/util.clj#L59-L73), and as a result there are some non-obvious consequences for numeric values calculated in the course of running a Push program.\r\n\r\nSo as far as I can see, more or less every function that \"returns an `integer`\" explicitly calls `keep-number-reasonable`, so the _de facto_ type we call a Push `integer` is a kind of truncated thing. Clojure will happily treat arithmetic (and other) numeric results as either boxed (fixed precision) or unboxed (arbitrary precision) values, and it looks also as if the basics of Clojush arithmetic uses arbitrary precision for results, but then inevitably applies `keep-number-reasonable` to that. Similarly, `float` values are protected by `keep-number-reasonable` from both the same overflow and also _underflow_—anything within some small $\\epsilon$ of `0.0` is rounded down to `0.0`.\r\n\r\nBut it is also true that if a `float` result is larger than `max-number-magnitude`, then `keep-number-reasonable` will convert it to an `integer`. You don't have to look at the tests I'm writing that surfaced this problem, but can [see this in the code itself](https://github.com/lspector/Clojush/blob/762721bdd5ade221e9a0530f167f194f5452a310/src/clojush/instructions/numbers.clj#L51). Whenever the value of `max-number-magnitude` is the default value of `1000000000000`, then the result of `(float_mult 10000000.0 10000000.0)` (or any larger `float` result) will be dropped down to the `integer` value `1000000000000`.\r\n\r\nAnd because the result of `keep-number-reasonable` is used inline within numeric instructions of several types, the `integer` will be present on the `float` stack as a result of `float_mult`. I suspect at least a few more of these are lurking in there for transcendental and exponential functions as well.\r\n\r\nSo what is `keep-number-reasonable` _really_ supposed to do? Can we be a bit more rigorous about its goal? For instance, can we pick a maximum precision for any Push `integer` value? I expect the origin of the truncation kludge is something about the way [Clojure handles numeric data type arithmetic](http://clojure.org/data_structures), and that you maybe were getting exceptions when `BigDecimal` results had infinite representations, but pure Java `float` primitives were overflowing and raising exceptions too?\r\n\r\nBut what do you want it to do, really? Besides \"not raise exceptions\"? At the moment it's injecting subtle and confusing ad hoc changes to running code. And there are no such checks and truncations on the \"routers\", so a _program_ that contains `2000000000000000000000` as a value would be perfectly runnable."},"comment":{"url":"https://api.github.com/repos/lspector/Clojush/issues/comments/149390417","html_url":"https://github.com/lspector/Clojush/issues/170#issuecomment-149390417","issue_url":"https://api.github.com/repos/lspector/Clojush/issues/170","id":149390417,"user":{"login":"Vaguery","id":81171,"avatar_url":"https://avatars.githubusercontent.com/u/81171?v=3","gravatar_id":"","url":"https://api.github.com/users/Vaguery","html_url":"https://github.com/Vaguery","followers_url":"https://api.github.com/users/Vaguery/followers","following_url":"https://api.github.com/users/Vaguery/following{/other_user}","gists_url":"https://api.github.com/users/Vaguery/gists{/gist_id}","starred_url":"https://api.github.com/users/Vaguery/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Vaguery/subscriptions","organizations_url":"https://api.github.com/users/Vaguery/orgs","repos_url":"https://api.github.com/users/Vaguery/repos","events_url":"https://api.github.com/users/Vaguery/events{/privacy}","received_events_url":"https://api.github.com/users/Vaguery/received_events","type":"User","site_admin":false},"created_at":"2015-10-20T01:08:19Z","updated_at":"2015-10-20T01:08:19Z","body":"> > Whenever the value of max-number-magnitude is the default value of 1000000000000, then the result of (float_mult 10000000.0 10000000.0) (or any larger float result) will be dropped down to the integer value 1000000000000.\r\n\r\n> I don't see this. If the result is a float then wouldn't keep-number-reasonable return (* 1.0 max-number-magnitude) which would be a float?\r\n\r\nNo, you're looking at the underflow. If the result of `float` multiplication is very large, the result of `keep-number-reasonable` is always an integer. "}}