实施7分频规则


25

要检查十进制数是否可以被7整除:

删除最后一位。将其乘以2并从剩余的值中减去。如果结果可被7整除,则原始数字可被7整除。

(例如也在此处描述)

此规则适用于手动除数检查。例如:

2016年是否可以被7整除?

减去6*2201;我们得到189。这是否可以被7整除?要检查它,让我们再次应用规则。

减去9*218;我们得到0。因此,2016被7整除。

在此挑战中,您应应用此规则,直到可分割状态明显,即该数字不大于70(但是,请参阅下面的详细信息)。制作功能或完整程序。

输入:正整数;您的代码应支持最多32767的输入(支持任意精度整数是一个加分项;请参见下文)。

输出:不大于70的整数(可能为负数),这是将7除数规则应用零次或更多次的结果。

测试用例:

Input                   Output      Alternative output

1                       1
10                      10          1
100                     10          1
13                      13          -5
42                      42          0
2016                    0
9                       9
99                      -9
9999                    -3
12345                   3
32767                   28          -14

---------- Values below are only relevant for the bonus

700168844221            70          7
36893488147419103232    32          -1
231584178474632390847141970017375815706539969331281128078915168015826259279872    8

如果指定了两个可能的输出,则任何一个结果都是正确的:第二个结果对应于再次应用该规则。禁止将规则应用于单个数字:如果删除该数字,则不会留下任何内容(非0)。


奖励:如果您的算法

n小数位数在哪里:

从代码的字节数中减去50%。

实际奖金

另外,如果您的算法从最高有效位开始沿正常方向读取输入,请再次减去50%-您的得分是字节数的25%(这似乎是可能的,但我不确定)。


1
@DenkerAffe可以按原样返回输入。我更新了input = 10的测试用例以反映这一点;从一开始就是这个主意。
anatolyg

4
我不想在上使用该规则1000000000000000000001
尼尔

1
但是,如果您的语言内置了long longs或某种等效类型怎么办?
SuperJedi224 '16

1
我的意思是,在某些实现中,它是一个128位整数,对于最后一个测试用例来说,它已经足够大了。
SuperJedi224 '16

7
-1。并非所有语言都支持任意精度。
3月Ho

Answers:


23

Golfscript,27个 22字节

{.9>{.10/\10%2*-f}*}:f

您可以通过以下方式使用它:

1000f

说明

{.9>{.10/\10%2*-f}*}:f
{                  }:f    # Define block 'f' (similar to a function)
 .                        # Duplicate the first value of the stack
  9>{            }*       # If the value on top of the stack is greater than 9 then the block is executed
     .10/\10%2*-          # Same as nb/10 - (nb%10 * 2) with some stack manipulations '.' to duplicate the top of the stack and '\' to swap the the first and second element of the stack
                f         # Execute block 'f'

感谢Dennis,节省了5个字节!


1
欢迎使用编程难题和Code Golf。这是一个很好的答案,但是您可以通过添加代码细目和解释来改进它,如上面的问题。要回复此评论,请在评论的开头(或其中的任何地方)键入@wizzwizz4@然后输入我的用户名)。
wizzwizz4 '02

1
@ wizzwizz4更好吗?我不确定我是否理解您所说的“代码故障”(不是对不起母语人士的意思)
Dica

8
我相信所谓的“代码故障”是指您已经添加的解释。确实,这是一个非常好的第一答案。欢迎光临本站!
Alex A.

1
您可以将{...}{}if部分重写为{...}*,这将根据施加的值仅将代码块零次应用一次>。另外,我们被允许再执行一次迭代(因此替换709保存一个字节),我认为您不需要使用弹出该块;
丹尼斯

3
@Dica,这是第一个很好的答案,足以对只有624次观看的问题进行12次以上的投票,并获得两位主持人的好评。如果继续努力,您很快就会超越丹尼斯!
wizzwizz4 '16

13

Haskell,35个字节

until(<71)(\n->div n 10-2*mod n 10)

用法示例:until(<71)(\n->div n 10-2*mod n 10) 36893488147419103232-> 32

无需多解释,它是算法的直接实现。


9

果冻,11个字节

d⁵Uḅ-2µ>9$¿

在线尝试!

怎么运行的

d⁵Uḅ-2µ>9$¿  Main link. Input: n

d⁵           Divmod; return [n : 10, n % 10].
  U          Upend; yield [n % 10, n : 10].
   ḅ-2       Convert from base -2 to integer, i.e., yield -2 × (n % 10) + (n : 10).

      µ      Push the previous chain as a link and begin a new, monadic chain.
          ¿  Apply the previous chain while...
       >9$     its return value is greater than 9.

和往常一样,果冻获胜。丹尼斯,在Jelly中实现果冻解释器需要多少字节?
巴林特

6

Python 2,38个字节

f=lambda x:f(x/10-x%10*2)if x>70else x

在这里尝试

简单的递归方法。如果x <70否则将应用除数规则并使用结果进行调用,则打印x。



@Maltysen是。复制粘贴错误的一个,谢谢提示!
Denker

2
if太冗长。f=lambda x:x*(x<70)or f(x/10-x%10*2)
seequ

1
@Seeq好招,谢谢!从理论上讲这应该可行,但是在输入2016时达到了最大递归深度,而我的版本则没有。知道为什么吗?
Denker

嗯,对,没有考虑。此技巧被认为x*(x<70) != 0是最终条件。如果x变为0(就像2016年一样),则最终条件永远不会发生。
seequ

6

Pyth,13个字节

.W>H9-/ZTyeZQ

在线尝试:演示测试套件

这将打印所有其他答案。

说明:

.W>H9-/ZTyeZQ   
            Q   read a number from input
.W              while
  >H9              the number is greater than 9
                do the following with the number:
      /ZT          divide it by 10
     -             and subtract
         yeZ       2*(number%10)

5

朱莉娅,27 26字节

f(x)=x>9?f(x÷10-x%10*2):x

这是一个递归函数,它接受整数并返回BigInt。如果输入如上例所示为大量,Julia会将其解析为BigInt,因此无需手动转换。

该方法只是该算法的直接实现。它将产生备用输出。当除以10时取模数可得出最后一位,而整数除以10的商将得到除最后一位之外的所有内容。

感谢Dennis,节省了一个字节!


我们可以再执行一次迭代,因此替换70为会9节省一个字节。
丹尼斯

@丹尼斯好的,谢谢!
Alex A.

4

Pyth,17个字节

L?<b70by-/bT*%bT2

在这里尝试!

python answer中的递归方法相同。定义一个lambda y,其名称如下:y12345
在线解释器中的字节计数器显示19个字节,因为我向其中添加了lambda调用,因此您可以通过点击运行按钮来尝试它。

说明

L?<b70by-/bT*%bT2

L                  # Defines the lambda y with the parameter b
 ?<b70             # if b < 70:
      b            # return b, else:
       -/bT*%bT2   # calculate b/10 - b%10*2 and return it

您的输入有错字,17应该是70:P
FryAmTheEggman

4

CJam-19个字节

同时执行的版本:

r~A*{`)]:~~Y*-_9>}g

在线或第1版时尝试

r~{_9>}{`)]:~~Y*-}w

在线或第2版时尝试

r~{_9>}{_A/\A%Y*-}w

在线尝试

r~                     | Read and convert input
  A*                   | Multiply by 10 to get around "if" rule
     `                 | Stringify
      )                | Split last character off
       ]               | Convert stack to array
        :~             | Foreach in array convert to value
          ~            | Dump array
           Y*          | Multiply by 2
             -         | Subtract
              _        | Duplicate
               9>      | Greater than 9?
    {            }g    | do-while

3

Oracle SQL 11.2,116字节

WITH v(i)AS(SELECT:1 FROM DUAL UNION ALL SELECT TRUNC(i/10)-(i-TRUNC(i,-1))*2 FROM v WHERE i>70)SELECT MIN(i)FROM v;

未打高尔夫球

WITH v(i) AS
(
  SELECT :1 FROM DUAL
  UNION ALL
  SELECT TRUNC(i/10)-(i-TRUNC(i,-1))*2 FROM v WHERE i>70
)
SELECT MIN(i) FROM v;

3

Haskell中,157 192 184 167 159 147 138 + 5个字节- 50%= 71.5字节

O(1)空间,O(n)时间,单遍!

h d=d%mod d 10
d%r=(quot(r-d)10,r)
p![d]=d-p*10
p![d,e]=d#(e-p)
p!(d:e:f)|(b,a)<-quotRem(2*d)10,(q,r)<-h$e-a-p=(b+q)!(r:f)
m#0=m
m#n=n-2*m
(0!)

用作0![6,1,0,2]将规则应用到2016年,即,以流形式将数字以最低有效数字首先传递给它。这样,它将逐位传递数字,应用具有O(1)空间复杂度的规则。

未启动的代码在这里:

import Data.Char

{- sub a b = sub2 0 a b
  where
    sub2 borrow (a:as) (b:bs) = res : sub2 borrow2 as bs
      where
        (borrow2, res) = subDig borrow a b
    sub2 borrow (a:as) [] = sub2 borrow (a:as) (0:[])
    sub2 _ [] _ = [] -}

--subDig :: Int -> Int -> Int -> (Int, Int)
subDig borrow a b = subDig2 (a - b - borrow)
  where
    subDig2 d = subDig3 d (d `mod` 10)
    subDig3 d r = ((r-d) `quot` 10, r)

seven ds = seven2 0 ds
seven2 borrow (d:e:f:gs) = seven2 (b + borrow2) (res:f:gs)
  where
    (a, b) = double d
    (borrow2, res) = subDig borrow e a
seven2 borrow (d:e:[]) = finalApp d (e-borrow)
seven2 borrow (d:[]) = d - borrow*10

double d = ((2*d) `mod` 10, (2*d) `quot` 10)

finalApp m 0 = m
finalApp m n = n - 2*m

num2stream :: Int -> [Int]
num2stream = reverse . map digitToInt . show
sev = seven . num2stream

其工作原理的要点是,它实现了逐位减法算法,但是利用了要减去的每个数字最多为2个数字这一事实,因此我们可以从这1个数字中减去任意数量主数字中的2位数字(以及食用最低有效数字)。

减法算法为O(1),仅存储当前的“借方”值。我对其进行了更改,以添加额外的数字(0或1),并且我们注意到此借位值是有界的(在[-2,2]范围内,因此我们只需要3位即可存储它)。

存储在内存中的其他值是临时变量,表示要添加的当前2位数字,在流中进行单次超前,并应用减法算法的一个步骤(即,它需要两位数字和一个借位值,然后返回一位数字和新的借入值)。

最后,最后它一次处理流中的最后两位数字,以返回一位数字而不是一位数字列表。

注意:sev非高尔夫版本中的功能将在上运行Integer,并将其转换为反向流形式。


我打算将奖金用于正常的数字顺序。但是我从来没有说过,因此,即使倒退的乐趣不大,也可以为冲销订单获得奖金。无论如何,即使颠倒的顺序也比我想的要难,所以很有趣!
anatolyg

@anatolyg:谢谢!我不确定是否可以执行正常顺序的单遍O(1)实现...该规则取决于最低有效数字,因此从理论上讲,除非以相反的顺序进行,否则直接应用该规则是不可能的。我唯一想到的另一件事是找到一个数学上等价的形式-例如Mod[18 - Quotient[n, 10] - 2*n, 21] - 18 + Quotient[n, 10]凭经验对n进行10到99的运算,但是n的位数越多,它就会变得更加复杂...
亚硝酸盐

嗯,我考虑了一下,似乎有一种方法可以保留前两位,然后再加上每个后一位,但是要乘以(-2)^ n来考虑它“通过” ...据我所知可以说,虽然没有办法,使这项工作不保持所有的数字都在内存中,牺牲O(1)“岬甚至O(N)”内斯...我认为正常秩序肯定是不行的:(

1
恐怕您0在调用时也必须计算首字母的字节!,例如,作为一个部分(0!)(+换行符),即+5字节。另一方面,您可以将第一个to模式匹配!p![d]=和缩短p![d,e]=。另外,请使用模式卫士,而不要使用letp!(d:e:f)|(b,a)<-quotRem(2*d)10,(q,r)<-h$e-a-p=(b+q)!(r:f)
nimi

1
@nitrous:哦,我只说(0!)了一点。(0!)是您给出答案的功能。将0是必需的,但无关的输入,所以你不能外包它给调用者。当然,您也可以使用f x=0!x,但这会更长。
nimi

3

GNU dc,20 15字节

[10~2*-d70<F]sF

这定义了我的第一个(曾经)直流功能F。它在堆栈顶部接受输入,而在堆栈顶部保留其输出。用法示例:

36893488147419103232
lFxp
32

2

Mathematica,47个 44字节

If[#>70,#0[{1,-2}.{⌊#/10⌋,#~Mod~10}],#]&

简单的递归方法。可能会打得更远。


#0[{1,-2}.QuotientRemainder[#,10]]保存一个字节。
njpipeorgan

2

R,43个字节

x=scan();while(x>70)x=floor(x/10)-x%%10*2;x

说明:

x=scan()                                      # Takes input as a double
        ;                                     # Next line
         while(x>70)                          # While-loop that runs as long x > 70
                      floor(x/10)             # Divide x by 10 and round that down
                                 -x%%10*2     # Substract twice the last integer
                    x=                        # Update x
                                         ;    # Next line once x <= 70
                                          x   # Print x

样品运行:

> x=scan();while(x>70)x=floor(x/10)-x%%10*2;x
1: 9999
2: 
Read 1 item
[1] -3

> x=scan();while(x>70)x=floor(x/10)-x%%10*2;x
1: 32767
2: 
Read 1 item
[1] 28

1

JavaScript ES6,38个字节

a=i=>i>70?a(Math.floor(i/10)-i%10*2):i

失败36893488147419103232和使用~~(1/10)也将失败700168844221

测试:

a=i=>i>70?a(Math.floor(i/10)-i%10*2):i
O.textContent = O.textContent.replace(/(-?\d+) +(-?\d+)/g, (_,i,o) =>
  _+": "+(a(+i)==o?"OK":"Fail")
);
<pre id=O>1                       1
10                      10
100                     10
13                      13
42                      42
2016                    0
9                       9
99                      -9
9999                    -3
12345                   3
700168844221            70
36893488147419103232    32</pre>


我得到两个Fail分数... 70和32
Conor O'Brien

@CᴏɴᴏʀO'Bʀɪᴇɴ是的,我仍然想知道为什么...
andlrc

因为JavaScript的数字类型至少不能处理最后一种情况。
Conor O'Brien

1
f=n=>n>70?f((n-n%10*21)/10):n是较短的版本,但仍适用于最高版本2**56
尼尔

@Neil看到我对任意精度的回答,请随时打高尔夫球,非常感谢。
帕特里克·罗伯茨

1

Mathematica,33个字节

#//.a_/;a>70:>⌊a/10⌋-2a~Mod~10&

测试用例

%[9999]
(* -3 *)

1

Perl 5,47 46字节

不得不bigint用于最后一个测试用例。(不返回20)

use bigint;$_=<>;while($_>9){$_-=2*chop;}print

不确定是否可以选择奖金,因此我没有考虑。(我认为是的,但我并不真正习惯这些概念)

在这里尝试!


1

ES6,108个字节

f=(s,n=0)=>s>1e9?f(s.slice(0,-1),((1+s.slice(-1)-n%10)%10*21+n-s.slice(-1))/10):s>9?f(((s-=n)-s%10*21)/10):s

适用于2²⁵⁷和1000000000000000000001,但可以进一步打高尔夫球。


@PatrickRoberts Oops,重新格式化提交时的监督。
尼尔

1

的JavaScript ES6,140个 142字节

f=s=>s>9?eval("t=s.replace(/.$/,'-$&*2');for(i=-1;0>(n=eval(u=t[c='slice'](i-4)))&&u!=t;i--);n<0?n:f(t[c](0,i-4)+('0'.repeat(-i)+n)[c](i))"):s

这是真正的任意精度数学,甚至适用于最大的测试用例。

此函数递归地删除字符串中的最后一位数字,然后通过迭代增加要应用于被减数的数字数量直到差值为正,从剩余的数字字符串中减去2 *最后一位数字。然后,使用适当填充的0s 将该差异附加到字符串的末尾,并递归调用自身,直到其数值小于或等于为止9

  • 感谢@Neil高尔夫球了7个字节(是的,我知道我增加了2个字节,但我修复了一些错误,在某些情况下,该错误导致函数冻结或返回错误的输出)。

f=s=>s>9?eval("t=s.replace(/.$/,'-$&*2');for(i=-1;0>(n=eval(u=t[c='slice'](i-4)))&&u!=t;i--);n<0?n:f(t[c](0,i-4)+('0'.repeat(-i)+n)[c](i))"):s;[['1',1],['10',1],['100',1],['13',-5],['42',0],['2016',0],['9',9],['99',-9],['9999',-3],['12345',3],['700168844221',7],['36893488147419103232',-1],['231584178474632390847141970017375815706539969331281128078915168015826259279872',8]].map(a=>document.write(`<pre>${f(a[0])==a[1]?'PASS':'FAIL'} ${a[0]}=>${a[1]}</pre>`))


不错,但可能无法正常使用1000000000000000000001
尼尔

1
尝试s.replace(/.$/,'-$&*2')。尽管抱歉,我对其余的事情没有任何明显的想法。
尼尔

1

C#,111104字节

int d(int n){var s=""+n;return n<71?n:d(int.Parse(s.Remove(s.Length-1))-int.Parse(""+s[s.Length-1])*2);}

1

Brain-Flak368360字节

在线尝试!

([([({})]<(())>)](<>)){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{}({}<>){{}(({}))(<((()()()()()){}<>)>)<>{({}[()])<>(({}()[({})])){{}(<({}({}))>)}{}<>}{}<>([([([(({}<{}><>)<([{}]{})(<((()()()()()){}(<>))>)<>{({}[()])<>(({}()[({}<({}())>)])){{}(<({}({}<({}[()])>))>)}{}<>}{}<>{}{}({}<>)>){}]{})]<(())>)(<>)]){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{}({}<>)}{}

说明

首先,所有代码处于循环中,直到堆栈的顶部小于零为止:

([([({})]<(())>)](<>)){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{}({}<>)
{{}
 ...
 ([([({})]<(())>)](<>)){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{}({}<>)
}{}

在循环内部,我们运行可除以七的算法:

复制堆栈顶部

(({}))

取栈顶的mod 10(最后一位)

(<((()()()()()){}<>)>)<>{({}[()])<>(({}()[({})])){{}(<({}({}))>)}{}<>}{}<>({}<{}><>)

这有点混乱,但是它完成了算法的其余部分,我可能会在以后解释,但是我并不完全记得它是如何工作的:

([(({})<([{}]{})(<((()()()()()){}(<>))>)<>{({}[()])<>(({}()[({}<({}())>)])){{}(<({}({}<({}[()])>))>)}{}<>}{}<>{}{}({}<>)>){}]{})

1

C,56个字节-75%= 14

尽管这没有提供与测试用例完全相同的数字,但是它满足了问题的实质(而且可以说更多)。它可以正确标识7的精确倍数,并给出其他数字的精确余数(因为它从未使用负数)。

n;f(char*c){for(n=0;*c;)n-=n>6?7:'0'-n-n-*c++;return n;}

该算法中没有乘法或除法,只有加法和减法,并且数字从左到右在一次传递中被处理。它的工作方式如下,从累加器中的0开始:

  1. 如有必要,减去7,如有必要,再减去
  2. 将运行总计乘以三,然后加上下一位

编写“三乘”步骤是n-=-n-n为了节省一个字节并避免乘运算符。

当我们结束时,我们不减去七,因此结果将在0-24范围内;如果你想有一个严格的模数(0-7),替代*c*c||n>6for循环条件。

它有资格获得增强的奖金,因为它

  • 支持任意精度整数
  • 按从左到右的顺序仅对输入执行一次传递
  • 具有空间复杂度O(1)
  • 具有时间复杂度O(n)。

测试程序和结果

#include <stdio.h>
int main(int argc, char **argv) {
    while (*++argv)
        printf("%s -> %d\n", *argv, f(*argv));
    return 0;
}
540 -> 15
541 -> 16
542 -> 17
543 -> 18
544 -> 19
545 -> 20
546 -> 21
547 -> 22
548 -> 23
549 -> 24
550 -> 18
99 -> 15
999 -> 12
12345 -> 11
32767 -> 7
700168844221 -> 7
36893488147419103232 -> 11
231584178474632390847141970017375815706539969331281128078915168015826259279872 -> 11

替代版本

这是递归的(您需要启用编译器优化以执行尾调用转换,否则可能会溢出堆栈;我使用过gcc -std=c89 -O3):

f(c,n)char*c;{return n>6?f(c,n-7):*c?f(c+1,n+n+n+*c-'0'):n;}

以“ 0”作为第二个参数调用它。

两种版本都在50毫秒内在我的计算机上计算出60,000位数字的余数模七。


感谢您的奖金-C如此有竞争力的真正改变!目前仅被果冻(11)和佩斯(13)击败。:-)
Toby Speight

1

PHP,50个字节

for($n=$argv[1];$n>9;)$n=$n/10|0-2*($n%10);echo$n;

使用替代输出;达到PHP_INT_MAX


字符串版本,适用于任何(正)数字(64字节):

for($n=$argv[1];$n>9;)$n=substr($n,0,-1)-2*substr($n,-1);echo$n;

0

Java,133个字节

int d(int n){String s=""+n;return n<71?n:d(Integer.parseInt(s.replaceFirst(".$",""))-Integer.parseInt(""+s.charAt(s.length()-1))*2);}

我讨厌这么冗长Integer.parseInt。取消高尔夫:

static int div(int n) {
    if (n <= 70) {
        return n;
    } else {
        String num = ("" + n);
        int last = Integer.parseInt("" + num.charAt(num.length() - 1));
        int k = Integer.parseInt(num.replaceFirst(".$", "")) - last * 2;
        return div(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.