比较四个整数,根据最大值返回单词


9

该函数应该采取四个整输入(abcd基于其值等于最大的四个),并返回一个二进制字。

返回值将在1和之间0xF

例如:

a = 6, b = 77, c = 1, d = 4

返回2(二进制0010;仅将第二最低有效位设置b为唯一的最大值)

a = 4, b = 5, c = 10, d = 10

返回0xC(二进制1100;第三个和第四个最低有效位设置对应于cd等于最大值)

a = 1, b = 1, c = 1, d = 1

返回0xF(二进制1111;因为所有值均等于最大值,所以设置了所有四个位)

这是一个简单的实现:

int getWord(int a, int b, int c, int d)
{
    int max = a;
    int word = 1;
    if (b > max)
    {
        max = b;
        word = 2;
    }
    else if (b == max)
    {
        word |= 2;
    }
    if (c > max)
    {
        max = c;
        word = 4;
    }
    else if (c == max)
    {
        word |= 4;
    }
    if (d > max)
    {
        word = 8;
    }
    else if (d == max)
    {
        word |= 8;
    }
    return word;
}

返回值可以是0和1的字符串,布尔/位向量或整数


2
我有一个使用高尔夫语言的解决方案,它使用了内置的反向,最大值,相等检查,联接,从二进制转换为整数,从整数转换为十六进制。这是否意味着通过平等检查我的分数是1?我觉得这太过专注于常规语言了,即使对于那些人来说,也不能100%清楚地说出“最大内置”的得分。。:S
凯文·克鲁伊森

1
我建议您尝试:1.将这个问题更改为code-golf,它只关心字节数。2.或者,限制为某种特定的语言(请使用特定版本的编译器/解释器),并列出所有允许的语句和运算符,以及如何对它们进行评分。
tsh

5
IMO是一个更好的选择。我认为这是一个完美的代码问题,而且我看不到限制可用于回答的语言会带来任何好处
senox13

2
我更新了问题以删除标准。让我知道这仍然不清楚
Anderson先生

5
我应该输出一个十进制数字吗?还是我可以输出4个二进制数字?
tsh

Answers:


8

果冻,2个字节

将输入作为[d,c,b,a]。返回布尔值列表。

Ṁ=

在线尝试!

中号 aximum

= 等于(暗示另一个参数是原始参数;向量化)


5

R,17个字节

max(a<-scan())==a

在线尝试!

返回布尔向量。由于已经确认了此输出,因此这比数字输出更好,因为输出时间几乎是数字的两倍:

R,33个字节

sum(2^which(max(a<-scan())==a)/2)

在线尝试!


4

APL(Dyalog Unicode),4 字节SBCS

匿名默认前缀功能。需要[a,b,c,d]作为参数。返回一个布尔布尔数组。*

⌈/=⌽

在线尝试!

⌈/ 请问参数的最大值

= 相等(向量)

 论点相反?

*请注意,APL使用每个值一个位来存储布尔数组,因此,尽管显示形式为,但这确实返回了一个4位字0 0 1 0



2

Perl 6、12个字节

{$_ X==.max}

在线尝试!

匿名代码块,它接受一个整数列表并返回一个布尔值列表。如果我们需要以数字形式返回,则需要+4个字节来将代码块的内部换行2:[...]

说明:

{          }  # Anonymous code block
 $_           # With the input
    X==       # Which values are equal
       .max   # To the maximum element

OP现在说您不需要包装。
亚当

2

Japt,5岁

m¶Urw

尝试一下!

-4字节感谢@Oliver!
-2个字节,感谢@Shaggy!

输入是采用以下格式的4元素数组:

[d, c, b, a]

输出是一个位数组。


当然有;)显然有很多学习捷径。
dana

如果布尔数组是可接受的输出,则可以为7个字节
Oliver

@ Oliver,5个字节;)
Shaggy

你们非常好:)有趣的是,如何通过反复获得最大值rw来转换成r("w")减少值。与转换为相同U.m("===", ...)。无论如何,感谢您的提示!
dana

2

x86机器代码(MMX / SSE1),26字节(4x int16_t)

x86机器码(SSE4.1),28字节(4x int32_t或uint32_t)

x86机器代码(SSE2),24字节(4x float32)或27B到cvt int32

(将int32转换为float的最后一个版本对于舍入到相同float的大整数并不是十分准确。使用float输入,舍入是调用者的问题,如果没有NaN,此函数将正常工作,以标识可比较==的float整数版本适用于所有输入,将其视为有符号2的补码。)

所有这些均以相同的机器代码在16/32/64位模式下工作。

使用stack-args调用约定可以使args循环两次(查找max然后进行比较),这可能为我们提供了一个较小的实现,但是我没有尝试过这种方法。

x86 SIMD将vector-> integer位图作为单个指令(pmovmskbmovmskpspd)使用,因此即使MMX / SSE指令的长度至少为3个字节也很自然。SSSE3和更高版本的指令比SSE2长,而MMX / SSE1指令最短。pmax*在不同的时间引入了不同版本的(最大整数垂直压缩),其中SSE1(用于mmx regs)和SSE2(用于xmm regs)仅具有带符号字(16位)和无符号字节。

pshufw以及pmaxswMMX寄存器是Katmai Pentium III的新增功能,因此实际上它们需要SSE1,而不仅仅是MMX CPU功能位。)

unsigned max4_mmx(__m64)与i386 System V ABI一样,它可以从C调用,后者在中传递__m64arg mm0。(不是x86-64 System V,它通过__m64xmm0!)

   line         code bytes
    num  addr   
     1                         global max4_mmx
     2                             ;; Input 4x int16_t in mm0
     3                             ;; output: bitmap in EAX
     4                             ;; clobbers: mm1, mm2
     5                         max4_mmx:
     6 00000000 0F70C8B1           pshufw    mm1, mm0, 0b10110001   ; swap adjacent pairs
     7 00000004 0FEEC8             pmaxsw    mm1, mm0
     8                         
     9 00000007 0F70D14E           pshufw    mm2, mm1, 0b01001110   ; swap high/low halves
    10 0000000B 0FEECA             pmaxsw    mm1, mm2
    11                         
    12 0000000E 0F75C8             pcmpeqw   mm1, mm0               ; 0 / -1
    13 00000011 0F63C9             packsswb  mm1, mm1               ; squish word elements to bytes, preserving sign bit
    14                         
    15 00000014 0FD7C1             pmovmskb  eax, mm1          ; extract the high bit of each byte
    16 00000017 240F               and       al, 0x0F          ; zero out the 2nd copy of the bitmap in the high nibble
    17 00000019 C3                 ret

size = 0x1A = 26 bytes

如果有一个pmovmskw,将保存packsswb和和and(3 + 2个字节)的内容。我们不需要,and eax, 0x0f因为pmovmskb在MMX寄存器上已经将高字节清零了。MMX寄存器只有8个字节宽,因此8位AL覆盖了所有可能的非零位。

如果我们知道输入是非负的,则可以packsswb mm1, mm0在的高4个字节中生成非负的有符号字节,从而mm1避免了需要andafter pmovmskb因此为24个字节。

带符号饱和的x86 pack将输入和输出视为带符号,因此它始终保留符号位。(https://www.felixcloutier.com/x86/packsswb:packssdw)。有趣的事实:具有无符号饱和的x86 pack仍将输入视为有符号。这可能就是为什么PACKUSDW直到SSE4.1才引入的原因,而自MMX / SSE2以来,存在尺寸和签名的其他3种组合。


或在XMM寄存器中使用32位整数(而pshufd不是pshufw),每条指令都需要再加上一个前缀字节,除了movmskps替换pack / and。但是pmaxsd/ pmaxud需要一个额外的额外字节...

可调用从C作为unsigned max4_sse4(__m128i);与x86-64的系统V,或MSVC vectorcall( -Gv),这两者都通过__m128i/ __m128d/ __m128在XMM暂存器ARGS开始xmm0

    20                         global max4_sse4
    21                             ;; Input 4x int32_t in xmm0
    22                             ;; output: bitmap in EAX
    23                             ;; clobbers: xmm1, xmm2
    24                         max4_sse4:
    25 00000020 660F70C8B1         pshufd    xmm1, xmm0, 0b10110001   ; swap adjacent pairs
    26 00000025 660F383DC8         pmaxsd    xmm1, xmm0
    27                         
    28 0000002A 660F70D14E         pshufd    xmm2, xmm1, 0b01001110   ; swap high/low halves
    29 0000002F 660F383DCA         pmaxsd    xmm1, xmm2
    30                         
    31 00000034 660F76C8           pcmpeqd   xmm1, xmm0               ; 0 / -1
    32                         
    33 00000038 0F50C1             movmskps  eax, xmm1          ; extract the high bit of each dword
    34 0000003B C3                 ret

size = 0x3C - 0x20 = 28 bytes

或者,如果我们接受输入为float,则可以使用SSE1指令。该float格式可以表示各种整数值...

或者,如果您认为规则过分弯曲,请从3字节0F 5B C0 cvtdq2ps xmm0, xmm0开始转换,然后制作一个27字节的函数,该函数适用于所有可完全表示为IEEE binary32的整数float,以及许多输入组合,其中一些输入可以在转换过程中四舍五入为2、4、8或其他倍数。(因此,它比SSE4.1版本小1个字节,并且可以在仅具有SSE2的任何x86-64上运行。)

如果任何浮点输入为NaN,请注意maxps a,b完全实现(a<b) ? a : b将第二个操作数中的元素保持为无序。因此,即使输入包含某些NaN(取决于它们的位置),也可能返回非零位图。

unsigned max4_sse2(__m128);

    37                         global max4_sse2
    38                             ;; Input 4x float32 in xmm0
    39                             ;; output: bitmap in EAX
    40                             ;; clobbers: xmm1, xmm2
    41                         max4_sse2:
    42                         ;    cvtdq2ps  xmm0, xmm0
    43 00000040 660F70C8B1         pshufd    xmm1, xmm0, 0b10110001   ; swap adjacent pairs
    44 00000045 0F5FC8             maxps     xmm1, xmm0
    45                         
    46 00000048 660F70D14E         pshufd    xmm2, xmm1, 0b01001110   ; swap high/low halves
    47 0000004D 0F5FCA             maxps     xmm1, xmm2
    48                         
    49 00000050 0FC2C800           cmpeqps   xmm1, xmm0               ; 0 / -1
    50                         
    51 00000054 0F50C1             movmskps  eax, xmm1          ; extract the high bit of each dword
    52 00000057 C3                 ret

size = 0x58 - 0x40 = 24 bytes

复制和随机播放with pshufd仍然是我们最好的选择:shufps dst,src,imm8读取dst from中 下半部分的输入dst。而且我们都需要非破坏性的复制和混洗,因此3字节movhlpsunpckhps/ pd都消失了。如果将范围缩小到标量最大值,则可以使用它们,但是如果我们还没有在所有元素中都具有最大值,则在比较之前要花费另一条指令进行广播。


相关信息:SSE4.1 phminposuw可以uint16_t在XMM寄存器中找到最小值的位置和值。我认为从65535中减去以将其用于最大数并不是一个胜利,但是看到关于将其用于最大字节数或带符号整数的SO答案


1

Python 3.8(预发布),67字节

Lambda函数采用4个整数,在Python 3.8的新赋值运算符的帮助下,将其比较的布尔结果移至最大值,然后返回结果的按位或

lambda a,b,c,d:((m:=max(a,b,c,d))==d)<<3|(m==c)<<2|(m==b)<<2|(a==m)

在线尝试!


:=让我想起了过去那是Lotus Notes公式的赋值运算符的地方。猜猜我不得不看一下3.8了:)
ElPedro



1

JavaScript(ES6),30个字节

将输入作为([d,c,b,a])。返回4个布尔值。

a=>a.map(x=>x==Math.max(...a))

在线尝试!


1
OP已阐明,您确实可以返回4个布尔值。
亚当


1

Python 3中59字节 66个字节

def f(l):
 n=max(a)
 for i in 0,1,2,3:a[i]=a[i]==n
 return a[::-1]

在线尝试!

将输入作为[a,b,c,d]并输出布尔值列表。

将其编辑为适当的函数,然后通过删除条件语句周围的方括号来节省2个字节。


1
您好,欢迎来到PPCG。就目前的情况而言,您的答案具有摘要的形式,这是不允许的。请修正您的答案以符合我们的I / O共识,即使其成为一个功能或完整的程序。
乔纳森·弗雷希

1
编辑。第一次来。欣赏头脑!
Bsoned

您可以使用lambda中的此列表理解将其减少到37个字节。欢迎来到PPCG,祝您逗留愉快!
价值墨水

@ValueInk删除多余的空格将节省另一个字节。
乔纳森·弗雷奇

1

1. Python 3.5,90个字节

将数字序列作为参数。返回“二进制”字符串

import sys;v=[*map(int,sys.argv[1:])];m=max(v);s=""
for e in v:s=str(int(e==m))+s
print(s)

例:

$ ./script.py 6 77 1 4 77
10010

说明

import sys
# convert list of string parameters to list of integers
v=[*map(int,sys.argv[1:])]
# get max
m=max(v)
# init outstring
s=""
# walk through list
for e in v:
    # prepend to outstring: int(True)=>1, int(False)=>0
    s=str(int(e==m))+s
# print out result
print(s)

1

C#(Visual C#交互式编译器),26字节

n=>n.Select(a=>a==n.Max())

在线尝试!

接受格式为的输入[d,c,b,a]。下面的所有其他内容都作为输入[a,b,c,d]

C#(Visual C#交互式编译器),35字节

n=>n.Select((a,b)=>n[3-b]==n.Max())

返回IEnumerable<bool>

在线尝试!

C#(Visual C#交互式编译器),39字节

n=>n.Select((a,b)=>n[3-b]==n.Max()?1:0)

返回一个IEnumerable<int>,代表位。

在线尝试!

C#(Visual C#交互式编译器),49字节

n=>{for(int i=4;i-->0;Write(n[i]==n.Max()?1:0));}

将二进制字符串输出到STDOUT。

在线尝试!


IEnumerable<bool> 可以接受的。
亚当

0

PHP,54字节

while($i<4)$argv[++$i]<max($argv)||$r+=1<<$i-1;echo$r;

要么

while($i<4)$argv[++$i]<max($argv)||$r+=1<<$i;echo$r/2;

从命令行参数获取输入。运行-nr在线尝试它们


0

这是一个以二进制输出的JS版本

更新:使用join时更短,并且没有查找:

JavaScript(Node.js),42字节

a=>a.map(x=>+(x==Math.max(...a))).join('')

在线尝试!

上一个,带有查询,49字节

a=>a.map(x=>[0,1][+(x==Math.max(...a))]).join('')

在线尝试!

上一个,带有reduce,为52个字节:

a=>a.reduce((y,x)=>y+[0,1][+(x==Math.max(...a))],'')

在线尝试!

fa=>a.map(x=>+(x==Math.max(...a))).join('')
console.log(f([ 4, 1,77, 6])) // 0010
console.log(f([10,10, 5, 4])) // 1100
console.log(f([ 1, 1, 1, 1])) // 1111


1
您可以放心删除,[0,1][...]因为您使用的索引已经是0 要么 1个
阿诺尔德

@Arnauld现在似乎很明显。谢谢!
Pureferret

0

C#(Visual C#交互式编译器),51字节

x=>{for(int m=x.Max(),i=4;i-->0;)x[i]=x[i]==m?1:0;}

在线尝试!

上面是一个匿名函数,它通过修改参数输出。输出是1和0的数组。

下面是一个输出整数的递归函数。

C#(Visual C#交互式编译器),60字节

int f(int[]x,int i=3)=>i<0?0:2*f(x,i-1)|(x[i]==x.Max()?1:0);

在线尝试!

这两个函数都将输入作为4元素数组。

[d, c, b, a]

您不需要输出整数。
亚当

@Adam-谢谢:)我在写其他答案时就意识到了这一点。在我有机会进行更改之前,还有一个C#答案,它使用了很多很好的技巧。
dana



0

批次,92个字节

@set m=%1
@set f=@for %%i in (%*)do @
%f%set/a"m=m+(m-=%%i)*(m>>31)
%f%cmd/cset/a!(m-%%i)

以相反的顺序将参数作为命令行参数。通过对参数的最大值进行折减并仅添加与运行最大值的正差来算术计算最大值,然后再次将每个参数与最大值进行比较以进行映射。便利cmd/cset/a不输出换行符,所以结果会自动连接在一起。在%f%简单地节省了这将是一个反复的构建5个字节。

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.