51

I'm using a "programming language" that only allows basic operations: addition, subtraction, multiplication, and division.

Is it possible to emulate a floor function (i.e. drop the decimals a number) by using only those operators? I'm only interested in positive numbers

Edit: Here's the documentation describing what's possible (which is only elementary arithmetic)

fregante
  • 629
  • 21
    Many programming languages will automatically floor when you divide two integers. – Arthur Dec 02 '14 at 11:48
  • 4
    You can't make comparisons in the program, can you? – Raskolnikov Dec 02 '14 at 12:13
  • 1
    By the way, another reference: http://www.w3.org/TR/css3-values/#calc-notation – Jean-Claude Arbaut Dec 02 '14 at 12:16
  • 3
    A bit roundabout, perhaps, but can you convert the type to a string? Then you'd be able to rip out the decimals with string operations and convert it back. – StephenTG Dec 02 '14 at 15:21
  • 3
    You might want to look into LESS (http://lesscss.org/), a CSS preprocessor which has floor, ceil and many more besides. – Dancrumb Dec 02 '14 at 15:54
  • 1
    I'm using Sass already but the rounding has to be done in the browser because I'm using percentages and pixel values. – fregante Dec 02 '14 at 16:09
  • 1
    How does the language handle type conversions? You might be able to get away with assigning an integer variable the value of a decimal number. – KSmarts Dec 02 '14 at 16:16
  • The language doesn't differentiate integers from other types. – fregante Dec 02 '14 at 16:24
  • 1
    You might also consider asking this on http://stackoverflow.com; perhaps the language provides some other obscure way to accomplish this. – Nate Eldredge Dec 02 '14 at 23:57
  • 1
    Usually if the answer in CSS involves round/floor/etc., you have to re-ask the question. What is it you're trying to do, exactly? – fluffy Dec 03 '14 at 07:42
  • @fluffy in using the "padding-top trick" to force an element to keep a set ratio. Unfortunately this doesn't always align correctly with the rest because of rounding error, pushing the next line of blocks one row down (using Packery with a fixed rowHeight). I ended up using margin-bottom:1px. I'll post a link when the site is published. – fregante Dec 03 '14 at 08:26
  • Related: http://stackoverflow.com/questions/25662159/chrome-37-calc-rounding – leonbloy Dec 03 '14 at 18:07
  • Can you maybe use the browser to do the rounding for you? Set an Integer-Only attribute to the value you calculated and read out that value again? Like invisible_element.some_attribute = x/c; real_element.attribute = invisible_element.some_attribute; - Maybe there are some attributes which are automatically rounded or floored ? – Falco Dec 04 '14 at 11:44

10 Answers10

48

Let $$f_1(x)=x+c_1$$ $$f_2(x)=x\cdot c_2$$ where $c_1,c_2$ are some constants, and $f_1$ represents addition and subtraction, and $f_2$ represents multiplication and division. Functions $f_1$ and $f_2$ have inverse function, but $\lfloor{x}\rfloor$ does not have an inverse function. So, if we assume it is possible to find $\lfloor{x}\rfloor$ from $x$ using $f_1$ and $f_2$, then it is possible to find $x$ from $\lfloor{x}\rfloor$. Contradiction.

  • 4
    Which means it's impossible, I suppose. I will start lobbying for a floor function, then! – fregante Dec 02 '14 at 11:55
  • 35
    If both possitive and negative numbers are supported, a map such as $x \mapsto x \cdot x$ is not invertible (and not constant either). So we can produces maps that are not invertible, in that case. Your $f_1$ and $f_2$ are functions of one variable, whereas addition and multiplications are functions of two variables. – Jeppe Stig Nielsen Dec 02 '14 at 13:06
  • 5
    Of course, even if we only have positive numbers, some polynomials are still not invertible. For example let $g(x) = (x \cdot x) + 5 - (4 \cdot x)$, then $g(1)=g(3)$. – Jeppe Stig Nielsen Dec 02 '14 at 13:13
  • 7
    Replace invertible by continuous then. – Sean D Dec 02 '14 at 21:22
  • @Jeppe Stig Nielsen. If I understood correctly, for multiplication at least one of the arguments must be a number (constant) and for division second argument must be a number (constant) and cannot be $0$, so $f_2$ have inverse function. –  Dec 02 '14 at 21:26
  • 2
    @Mathematician171 the OP said the programming language allows arithmetic operations like multiplication and division. So $f_3(x) = x \cdot x$ would be among the tools that could hypothetically be used. (In the general case a computer running a set of instructions on memory registers has no concept of one of its operands being "constant" in the sense of your $c_1$ and $c_2$.) – jez Dec 02 '14 at 23:29
  • 1
    @jez. Can you explain the meaning of statement "At least one of the arguments must be a " which is given on the link in the question? –  Dec 02 '14 at 23:45
  • 1
    My mistake: you're right, it really looks like it can only implement invertible functions. +1 for the nice proof. – jez Dec 03 '14 at 00:11
  • 2
    @Mathematician171: <number> refers to one of the types available. Other types include <length> and <time>; the documentation is saying you can't do things like divide by a length or multiply two times. Note that it explicitly says that a calc expression may be used wherever <number> values are allowed, so you can put a calc as the right-hand argument of a division in another calc. – user2357112 Dec 03 '14 at 03:17
  • A lovely, simple explanation that made me facepalm for not having thought of it myself – Mark K Cowan Dec 03 '14 at 14:44
  • 9
    -1, I do not think this argument is correct. And regardless of whether it is correct or not, we need to demand more rigor from answers on a math site. For one thing, the link does not specify that one of the arguments in addition must be a , so your part about $f_1$ is just wrong. For another thing, I think you have the wrong understanding of ; the correct meaning of is pointed out by user2357112. – Caleb Stanford Dec 03 '14 at 21:03
  • -1. You can make arbitrary polynomials with the given operations, and not all polynomials are invertible. – Nick Matteo Dec 05 '14 at 03:21
  • 1
    Given that an actual programming language probably works with floating point, not actual rational numbers or better, neither $f_1$ nor $f_2$ is invertible. – R.. GitHub STOP HELPING ICE Dec 05 '14 at 04:08
  • Multiplication doesn't have inverse function for $c_2 = 0$. – Tomas Dec 05 '14 at 12:06
  • -1. You only proved that affine functions are not invertible. The given operations define an algebraic space. – Tom-Tom Mar 06 '15 at 12:20
  • 1
    -1, this argument doesn't hold at all. Replace $\lfloor{x}\rfloor$ with $x^2$. All the same premises hold, $x^2$ does not have an inverse function... yet $x^2$ is derivable from the given operations. – Don Hatch Nov 25 '18 at 07:38
45

The floor function has jump discontinuities.

A function obtained with elementary arithmetic is a rational function and those can only have pole (or infinite) discontinuities.

lhf
  • 216,483
  • But actual arithmetic implementations also have discontinuities. – Ben Voigt Dec 02 '14 at 17:18
  • 5
    @BenVoigt Then the specification is wrong, which talks specifically about "Addition", "Subtraction", "Multiplication", "Division". Even in the presence of rounding errors, the precision is not specified. – Hagen von Eitzen Dec 02 '14 at 19:00
28

Yes it is possible, but depends on the available arithmetic and the rounding mode. With IEEE-double you can round a double $x$ to the nearest integer with this:

$c=2^{52};$

$x = x + c; \mathrm{round} = x - c$ for $x\ge 0\;$ and

$x = x - c; \mathrm{round} = x + c$ for $x<0.$

With the rounding to the next integer you can implement floor.

smci
  • 364
gammatester
  • 18,827
  • 7
    Just a warning for the OP: the precision in CSS (for which this question is asked) is theoretically infinite, in which case this answer would be meaningless, but in practice numbers are supposed to have "reasonably useful ranges and precisions", which will vary across implementations, even across different versions of the same browser. – hvd Dec 02 '14 at 12:31
  • 3
    You are onto something as calc(2.9999px + 9007199254740992px - 9007199254740992px) actually produces 2px in Chrome ($c=2^{53}$)! As @hvd said this is likely to depend on the implementation but I can run some tests. Worst case scenario I cause the browser to crash /s – fregante Dec 02 '14 at 14:18
  • Firefox on the other hand caps at $c=2^{24}$, which kind of breaks this solution (anything higher produces 0) – fregante Dec 02 '14 at 15:08
  • @bfred.it: That doesn't necessarily break it. How did you test? Can you link me a fiddle or something I can meddle with a little? Because when I try, the browser seems to be rounding everything to the nearest px. – Ben Voigt Dec 03 '14 at 00:03
17

If you can use a loop and extra variables, you can repeatedly subtract one until left with only the decimal part.

Something like:

floor(x):
floor = 0
While x >= 1
    floor += 1
    x -= 1
End While

Not the greatest, and will take a long time for large numbers, but it could be tweaked.

It also won't work for negative values, but that's easily fixed.

Brian J
  • 319
12

You can do integer division using complex arithmetic, but there's a different function for each divisor. For example,

$$\left\lfloor \frac{x}{2} \right\rfloor = \frac{x}{2} - \frac{1 - (-1)^x}{4} $$

for $x$ an integer. For higher $k$ you'll use $k$th roots of unity.

Mitch
  • 8,591
  • 1
    This solution requires exponentiation, which is not among the allowed operations. – Christian Semrau Dec 03 '14 at 22:30
  • @ChristianSemrau the given ops do not allow complex math (exact, not floating point) or arbitrary roots of unity either. The true answer is either 'no' because of the reason given in the top answer, or 'yes' because the domain is integers and integer division already gives the floor. – Mitch Dec 03 '14 at 22:54
  • Indeed. Seeing that the indented programming language is CSS, neither is allowed, and the answer is no. – Christian Semrau Dec 03 '14 at 23:05
  • @Mitch Is there a generalization of this formula ($\lfloor \frac{m}{n} \rfloor$ for $m,\ n$ integer, for instance)? A reference to this idea is also appreciated. – Felix Fourcolor Nov 06 '18 at 18:24
9

For overkill, if you also have sine you can use the Fourier expansion:

$$\lfloor x \rfloor = x- \frac{1}{2} + \frac{1}{\pi} \sum_{k=1}^{\infty} \frac{\sin 2 \pi k x}{k}$$

(except when $x$ is already an integer, I think). If you don't have sine you can build that up using a Taylor's series. Also $\pi$.

Mitch
  • 8,591
  • Since all your ops are on integers, the output of each op will be integers. The default implementation of integer division and so will be to 'round to 0' which is equivalent to 'floor' on non-negative integers. Which means you don't need a special 'floor' function because you already have it by default. – Mitch Dec 02 '14 at 20:09
4

If you are able to use a javascript library as well as CSS (maybe not possible if you are using something like eBay) you can use http://lesscss.org/functions/ to extend your CSS to allow a floor function.

2

Programming languages typically use floating-point arithmetic defined by the IEEE 754 standard. Roughly speaking, if the exact result of an operation calculated using mathematical real arithmetic has an absolute value $2^k ≤ x < 2^{k+1}$, then x will be rounded to the nearest integer multiple of $2^{k-52}$. The exception is the case where x is exactly between the two nearest integer multiples of $2^{k-52}$, in which case x will be rounded to the even multiple.

If the absolute value x is between $2^{52} ≤ x < 2^{53}$, then x will be rounded to the nearest integer or the nearest even integer if x is exactly between two integers. Any floating-point numbers with an absolute value $x ≥ 2^{52}$ are actually integers. And any floating-point operation where the exact result is an integer with $-2^{53} ≤ x ≤ 2^{53}$ will give the exact result.

This gives a simple implementation: If the absolute value of x is $2^{52}$ or greater then x is an integer and floor (x) = x. Otherwise; first add then subtract $2^{52}$ from x if x >= 0, but first subtract then add $2^{52}$ to x if x < 0. This rounds x to one of the two nearest integers. If the result is greater than the original value of x, subtract 1.

I think this is quite close to the implementation that is typically used by current compilers.

gnasher729
  • 10,113
0

try modulo 1 : x=x-(x mod 1) It works with both + and - numbers.

Gerald
  • 33
0

I know I'm a little late to this party but thought it was worth noting that given a basic round function you can find the floor by doing round(x - .5)