弹跳取模两个数字


12

模运算()的图形如下所示:y=xmodk

模函数图

这是一个非常有用的功能,因为它允许我们创建“包装”行为。但是,当我要使用它在两堵墙之间创建“反弹”外观时,这非常麻烦。“反弹”功能的图形(y=bounce(x,k))如下所示:

“反弹模数”功能图

的图的周期为。的图的周期为,因为在返回到起点之前,它向上移动单位,然后向下移动另一个单位。对于这两个函数,的最小值均为0,最大值为(实际上,对于具有积分输入的模数函数,其)。另外,对于这两个函数,值为0。k y = 跳动x k 2 k k k y k k 1 x = 0y=xmodkky=bounce(x,k)2kkkykk1x=0

挑战

给定一个整数和一个正整数,返回的整数或浮点近似值。k y = 跳动x k xky=bounce(x,k)

这是,因此最短的有效提交(以字节为单位)获胜。

测试用例

  x,  k -> bounce(x, k)
  0, 14 ->            0
  3,  7 ->            3
 14, 14 ->           14
 15, 14 ->           13
-13, 14 ->           13 (12.999997 etc would be an acceptable answer)
-14, 14 ->           14
191,  8 ->            1
192,  8 ->            0

为奖励积分傅立叶为基础的做法,傅立叶


对于这两个函数,x的最小值均为0,而最大值为k ”是完全错误的。
彼得·泰勒

@PeterTaylor哎呀。我的意思是结果。
硕果累累

1
糟糕,这就是我已经说过的。还是错 k % k = 0
彼得·泰勒

@PeterTaylor哦,我了解您的问题。我最初在设计时就考虑了浮点数,然后切换到整数。将进行编辑。
硕果累累

1
@PeterTaylor如果参数为浮点型,则最大值为任意接近的数字k
硕果累累

Answers:


7

x86-64机器码,18字节

97
99
31 D0
29 D0
99
F7 FE
29 D6
A8 01
0F 45 D6
92
C3 

这段代码使用x86-64机器语言定义了一个计算的函数bounce(x, k。遵循Gnu / Unix系统上使用的System V AMD64调用约定x参数在EDI寄存器中传递,而k参数在ESI寄存器中传递。与所有x86调用约定一样,结果将返回到EAX寄存器中。

要从C调用此函数,您可以将其原型如下:

int Bounce(int x, int k);

在线尝试!

非高尔夫装配助记符:

; Take absolute value of input 'x' (passed in EDI register).
; (Compensates for the fact that IDIV on x86 returns a remainder with the dividend's sign,
; whereas we want 'modulo' behavior---the result should be positive.)
xchg   eax, edi      ; swap EDI and EAX (put 'x' in EAX)
cdq                  ; sign-extend EAX to EDX:EAX, effectively putting sign bit in EDX
xor    eax, edx      ; EAX ^= EDX
sub    eax, edx      ; EAX -= EDX

; Divide EDX:EAX by 'k' (passed in ESI register).
; The quotient will be in EAX, and the remainder will be in EDX.
; (We know that EAX is positive here, so we'd normally just zero EDX before division,
; but XOR is 2 bytes whereas CDQ is 1 byte, so it wins out.)
cdq
idiv   esi

; Pre-emptively subtract the remainder (EDX) from 'k' (ESI),
; leaving result in ESI. We'll either use this below, or ignore it.
sub    esi, edx

; Test the LSB of the quotient to see if it is an even number (i.e., divisible by 2).
; If not (quotient is odd), then we want to use ESI, so put it in EDX.
; Otherwise (quotient is even), leave EDX alone.
test   al, 1
cmovnz edx, esi

; Finally, swap EDX and EAX to get the return value in EAX.
xchg   eax, edx
ret

请注意,第一部分(采用绝对值)可以等效地编写为:

; Alternative implementation of absolute value
xchg    eax, edi
neg     eax
cmovl   eax, edi

完全相同的字节数(6)。性能应该相似,也许会稍快(有条件移动较慢的某些Intel芯片除外)。

XCHG当然,它是相对较慢的,MOV除了在代码打高尔夫球中(在操作数之一是累加器的情况下,前者是1字节,而在寄存器中的寄存器MOV始终是2字节)时,它是不可比的。


6

果冻,3个字节

æ%A

在线尝试!

内置ftw。

说明

æ%是一个有用的内置工具。我不知道如何描述它,所以我只提供一些输入的输出:

由于x从去0到无穷远,xæ%40,1,2,3,4,(-3,-2,-1,0,1,2,3,4,)那里括号中的部分被重复无限两种方式。




3

Ruby,40字节 32字节

b=->(x,k){(x/k+1)%2>0?x%k:k-x%k}

在线尝试!

说明

嗨,这是我在本网站上的第一个答案!该代码基于以下观察结果:当(n -1)k <= x < nk且n为奇数时,弹跳函数的行为与模数完全相同,而当n为偶数时,弹跳函数的行为类似于逆模运算。 (x/k+1)是大于x / k的最小整数(x / k +1向下舍入为整数)。因此,(x/k+1)找到上述n%2>0检查n是否为奇数或偶数。如果n mod 2> 0,则n为奇数。如果nmod 2 = 0,则n为偶数。如果n为奇数,则反弹功能应等于x mod k。如果n为偶数,则反弹函数应为反函数,等于k - x mod k。整个表达式(x/k+1)%2>0?x%k:k-x%k找到n,然后执行x mod k(如果为奇数),否则执行k - x mod k

根据Cyoce的建议,答案得到了改善。


您可以将其转换为lambda。代替def b(x,k) ... end使用->x,k{...}
Cyoce '17

而且由于您要处理整数,.to_i所以没有必要。
Cyoce



1

J,25个字节

暗示:

这只是阶梯数的常规模。例如,对于5:0 1 2 3 4 5 4 3 2 1

这是J中的一种解决方案(尚未完善),明天将尝试改进:

[ ((|~ #) { ]) (i.@>:,}:@i.@-) @ ]

压缩: [((|~#){])(i.@>:,}:@i.@-)@]

压缩2: [((|~#){])(<:|.|@}.@i:)@]

在线尝试!


我觉得i:可以在这里使用,但是我还没有尝试过解决方案
Conor O'Brien

@ ConorO'Brien检出我的compression2版本,它使用保存了一些字节i:。只是没有时间更新主要版本并提供解释。我希望专家至少可以减少4或5个字节...
乔纳

((|~#){])]-|@}:@i:18字节
英里

@miles美丽,tyvm
约拿(Jonah)

1

QBIC25 30 27字节

g=abs(:%:)~a'\`b%2|?b-g\?g

做了一些重组...

说明

g=abs(   )  let g be the absolute value of 
       %    the (regular) modulo between
      : :   input a read from cmd line, and input b read from cmd line
~a \ b%2    IF the int division of A and B mod 2 (ie parity test) yields ODD
  ' `         (int divisions need to be passed to QBasic as code literals, or ELSE...)
|?b-g       THEN print bouncy mod
\?g         ELSE print regular mod

QBIC在MOD操作方面是否与其他基本实现有所不同?其他基础知识返回的MOD与股息相同。当将失败x为-13,并k为14
科迪灰色

@CodyGray不,它给-13。立即修复。
steenbergh

你们都不需要abs两次吗?
尼尔

@Neil有一个测试用例吗?
steenbergh

@Neil nvm,我已经通过重组整个问题解决了它。
steenbergh

1

C89,40个字节

t;f(x,k){t=abs(x%k);return x/k%2?k-t:t;}

我的x86机器代码答案的 AC端口,它定义了一个函数,该函数f计算参数x和的反弹模数k

它使用C89的隐式int规则,因此两个参数,全局变量t和函数的返回值都隐式为type intt与在条件运算符的任一侧重复计算相比,全局变量仅用于保存一个临时值,最终节省了字节。

abs函数(绝对值)在所提供的<stdlib.h>头部,但我们没有再在这里,包括它得益于C89的隐含-INT规则(其中函数是隐式声明,并假设其回报int)。

在线尝试!

非高尔夫版本:

#include <stdlib.h>

int Bounce(int x, int k)
{
    int mod = abs(x % k);
    return (x/k % 2) ? k-mod : mod;
}

根据我手工调整的机器代码来看,编译器实际上为此生成了相当不错的输出。我的意思是,他们应该;这是一个非常简单的优化功能!但是,我确实发现了GCC x86-64优化器中的一个小错误,当您告诉它优化大小时,它会奇怪地生成较大的代码,而告诉您优化速度时,它会生成较小的代码。


m;f(x,k){m=abs(x%k);x=x/k%2?k-m:m;}
user41805

除了由于在x86目标上GCC代码生成器的古怪而在某些不确定的情况下,它实际上不返回值@cows。这是我在这里看到的人使用的模板,但是对我来说不起作用,除了将随机垃圾从堆栈中拉出来,而这恰好是正确的答案。
科迪·格雷

1

Haskell,37字节

在线尝试!

(!)=mod;x#k|odd$x`div`k=k-x!k|1<2=x!k

使用方法:
调用as 15#14作为非负的左参数,并作为(-13)#14负的左参数,因为Haskell会解释-13#14-(13#14)好像使用的是ghci。TIO链接仅接受两个命令行参数。

说明:
首先将二进制中缀运算符重新定义!为与相同mod。Haskell mod始终输出非负值,因此我们不需要abs此处的其他解决方案。然后,它检查x/k(整数除法)是否为奇数,如果为奇数,则返回k-x mod k(即反跳),否则返回x mod k


这可能只是一个口味问题,但是我个人更喜欢不进行定义,!因为它不会保存任何字节x#k|odd$x`div`k=k-x`mod`k|1<2=x`mod`k
Mark S.17年

1

PHP,40 50字节

该死的美元。该死的导入开销。:)

整数版本:

[,$x,$k]=$argv;$y=abs($x)%$k;echo$x/$k&1?$k-$y:$y;

要么

[,$x,$k]=$argv;echo[$y=abs($x)%$k,$k-$y][$x/$k&1];

浮动版本,56个字节:

替换abs($x)%$kfmod(abs($x),$k)


编辑:固定结果为负 x


4
“该死的美元”。是的,钱很臭……
steenbergh

2
怎么样€argv还是£argv?那些看起来不错:x
Ismael Miguel

1

JavaScript(ES6),36 32字节

k=>f=x=>x<0?f(-x):x>k?k-f(k-x):x

递归反弹x反对0k,所以非常的挑战精神。



0

C(gcc),43 53字节

编辑:修复了负面问题

int f(int x,int y){return x/y%2?abs(y-x%y):abs(x%y);}

在线尝试!


2
这为(-13,14)(-13而不是13)提供了错误的答案。模数和余数运算在负数上表现不同。
CAD97

0

R,28个字节

pryr::f(abs((x-k)%%(2*k)-k))

对函数求值:

function (k, x) 
abs((x - k)%%(2 * k) - k)

这似乎是大多数解决方案使用的方法。在做这个之前我没有看过他们。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.