如何使用模运算符来包装一个数字

3

不确定是否可能,但是否有一种自动的方式,使用mod或类似的东西,来自动纠正错误输入值?例如:

If r>255, then set r=255 and
if r<0, then set r=0

所以基本上我的问题是,有没有一个巧妙的数学方法来设置这个,而不是使用。
if(r>255)
 r=255;
if(r<0)
 r=0;

对于未来的回答者,我认为提问者想要在没有条件语句的情况下完成此操作。这意味着不允许调用MAX或MIN函数。 - Olhovsky
嗯,我之前想过可能有一个很酷的数学方法来解决这个问题,但我猜任何独特的捷径都可以,尽管MIN和MAX基本上是条件语句。 - Snowman
你是只出于好奇还是想要提速或者更好的美观性? - Olhovsky
5
"Wrap" 是一种不同的操作。这个操作被称为“饱和”或者“夹紧”。 - ruslik
1
我同意@ruslik的看法。能否更改问题的标题,去掉“wrap”这个词,而使用取模作为优雅的数学解决方案?否则像我这样的人会一直在这里寻找wrap的答案。 - Rick Henderson
5个回答

7
如何呢:
r = std:max(0, std::min(r, 255));

2
以下函数将输出您要查找的内容:
 f(x) = (510*(1 + Sign[-255 + x]) + x*(1 + Sign[255 - x])*(1 + Sign[x]))/4

如下图所示:

enter image description here


这张图片展示了:

那么你是如何实现 Sign 的呢 :-) - stefan
@stefan 许多方法可以实现,如果它不是一个原始数据类型。例如 Sign[x]=x/Abs[x] (当 x 不等于 0)。 - Dr. belisarius
@belisarius 我同意Kdoto的看法 >D 但是有了Mathematica在手,我想我们可以坐在这里度过整个千年;-) - stefan
@stefan 那真的那么糟糕吗?:D - Dr. belisarius
@belisarius Mathematica?确实是的。我有一个巨大的PDF文件,里面有一些讨厌的迭代积分,我不知道该从中找到什么。当Mathematica给出"\[Pi]"作为答案时,我惊呆了一个月。 - stefan
@stefan 在 SO 社区里有一个非常友好和乐于助人的 Mathematica 用户群体。如果您有任何问题,请毫不犹豫地在 [mathematica] 标签下提问。 - Dr. belisarius

0

你能做类似这样的事情吗 --

R = MIN(r, 255);
R = MAX(R, 0);

那行不通。R总是会是零或负数。 - ClosureCowboy
你把MIN和MAX搞反了,结果总是0。 - Martin York
1
即使这样可以工作,它并没有真正回答问题。MAX和MIN具有条件语句,而提问者正试图避免使用它们。 - Olhovsky
@Kdoto:我不确定标准规定了min/max的实现方式。OP要求巧妙的数学方法。min/max是相对标准的数学函数。我怀疑这个问题与速度无关,更多地涉及美学方面。 - Martin York

0

根据您的硬件和可能的解释器处理整数的方式,您可以这样做:

假设无符号整数为16位(以保持掩码短):

r = r & 0000000011111111;

如果int是32位的,你需要在位掩码的开头再加16个零。
在进行按位与运算之后,r的最大值为255。根据硬件的不同,如果给无符号整数赋一个小于零的值,可能会出现一些奇怪的情况。我相信这种情况已经被位掩码处理了(至少在我使用的硬件上是这样)。如果没有,你可以先执行r = min(r, 0);

1
你在问题中假设了一些未提及的内容。你不知道这个数字是如何以二进制形式描述的。 - stefan
1
我想是这样。到目前为止,这是我看到的唯一一个提供效率增益而不仅仅是美学增益的答案。所以我认为值得一提。不过你说得对 - 我确实假设r以有限可屏蔽的形式存储 - 这是我在SO上看到的每个问题的情况。我在我的答案中写道“假设无符号整数为16位”。 - Olhovsky
1
如果这能让你感觉更好,你可以将同样的逻辑应用于一个有无限位数字的数值,只要你知道该数字所代表的结构,并且能够对该数字形成掩码。 - Olhovsky
@Kdoto 你知道就好了,不是我给你的帖子点了踩。 - stefan
@stefan,谢谢。我没有假设你这样做了。 - Olhovsky

0

我在处理图像时遇到了类似的问题。对于一些特殊值(比如0和255),你可以使用这种不可移植的方法:

static inline int trim_8bit(unsigned i){
    return 0xff & ((i | -!!(i & ~0xff))) + (i >> 31);
    // where "0xff &" can be omitted if you return unsigned char
};

在实际情况中,夹紧操作很少需要执行,因此您可以编写
static inline unsigned char trim_8bit_v2(unsigned i){   
    if (__builtin_expect(i & ~0xFF, 0)) // it's for gcc, use __assume for MSVC
        return (i >> 31) - 1; 
    return i;
};

为确保哪个最快,测量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接