请注意,虽然它听起来很相似,但这不是常见的"如何将一个矢量旋转到另一个矢量"问题.
我想从两组3个点得到一个仿射变换(矩阵或四元数+矢量形式).这些可以被视为刚体上的"标记点",或者作为"向前和向上"向量的端点.翻译和旋转是必要的,缩放不是必需的.此外,四元数+向量解决方案将是一个加号,因为它将允许我将1/3多个实例塞入绘图批次(8个制服而不是12个).目的是建立一个系统,以直观的方式确定(铰接的或非铰接的)身体的姿势,而不需要维护和行走复杂的层次结构.
第一个明显的简化是通过选择一个点并从相应的"开始"点减去"目的地"来消除平移部分.现在我们只需要处理轮换.
有一种众所周知的,计算上廉价的构造四元数的解决方案,它将一个矢量旋转到另一个矢量上,即q(交叉(v1,v2); sqrt(v1.len_sq*v2.len_sq)+点(v1,v2))或q(cross(v1,v2); 1 + dot(v1,v2))用于单位长度矢量.不幸的是,这种方法没有"向上方向"的概念,因此总是在最短的弧上旋转(这将使对象不对齐).天真的做法是简单地将这种方法用于两个向量并将四元数相乘,但显然它不会那么容易.需要做的是选择两个向量中的一个(让我们称之为"向前"),并为此创建一个四元数,然后使用此四元数旋转另一个("向上")向量,然后构造第二个四元数对于旋转的"向上"向量(和目标"向上"向量),最后将第二个乘以第一个四元数.据我所知,这是正确的,但它也非常复杂.
现在......至于旋转矩阵,我知道"三元组方法",我理解如下: - 对矢量对(开始和结束)进行正交化 - 这导致两个正交基,它们是相应的旋转矩阵,用于启动并从"共同参考框架"结束.这究竟是什么参考框架并不重要,重要的是两者都是相同的. - S是从"公共帧"到起始帧的变换,D是到结束帧的变换.- 因此,S -1*D*v转换从开始到结束坐标系的任何点(通过公共参考系).- S -1 == S T因为它是一个标准正交矩阵,并且S T*x = x*S - 因此:S T*D*v = D*S*v
这应该可行,但对于实际上应该非常非常简单的事情来说,它似乎仍然相当复杂.
有更简单,更直接的解决方案吗?
我想在应用程序启动时添加调整屏幕gamma的功能,并在退出时重置它.虽然人们是否应该篡改伽玛是有争议的(个人我发现它毫无用处和有害),但是嘿,有些人希望能够做那种事情.
这只是一个简单的API调用,所以这很容易,对吧?
MSDN说:"伽马斜坡在三个256个WORD元素阵列中指定,每个值必须存储在每个WORD的最高有效位中,以增加DAC的独立性." .在我的理解中,这意味着,word_value = byte_value<<8听起来很奇怪,但这就是我读它的方式.
Doom3源代码包含一个函数,它接受三个char值数组并将它们转换为一个uint16_t值数组,这些值在上半部分和下半部分都具有相同的字节值.换句话说就像word_value = (byte_value<<8)|byte_value.这同样很奇怪,但更糟糕的是它与上面的不一样.
互联网上还有一些代码片段在各种爱好程序员网站上(显然是一个从另一个被盗,因为它们与字母相同),这些代码片段做了一些模糊的数学运算,将线性指数乘以一个值,偏差为128,并且夹到65535.我不太确定这是什么,但对我来说这看起来完全是胡说八道,而且它与上述两者中的任何一个都不一样.
是什么赋予了?必须明确定义 - 不要猜测 - 您提供的数据必须如何?最后,人们会做的是读取原始值并让用户无论如何调整一些滑块(并且可选地使用用户的配置将该blob保存到磁盘),但仍然......为了修改这些值,需要知道他们是什么,期待什么.
有人做过(并经过测试!)之前知道哪一个是对的吗?
(可能与如何实现创建新对象的C++方法有关,并返回对它的引用,该引用是关于不同的东西,但在内部包含几乎完全相同的代码)
我想从静态函数返回对静态局部的引用.当然,我可以让它上班,但它并不像我想的那么漂亮.
这可以改善吗?
我有几个类,其没有做很多,除了获得或在一个明确的方式,可靠地初始化资源,然后将其释放.他们甚至不需要了解资源本身,但用户可能仍希望以某种方式查询某些信息.
这当然是琐碎的:
struct foo { foo() { /* acquire */ } ~foo(){ /* release */ } };
int main()
{
foo foo_object;
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
不重要的.或者,这也可以正常工作:
#include <scopeguard.h>
int main
{
auto g = make_guard([](){ /* blah */}, [](){ /* un-blah */ });
}
Run Code Online (Sandbox Code Playgroud)
除了现在,查询东西有点难,而且它不如我喜欢的漂亮.如果你更喜欢Stroustrup而不是Alexandrescu,你可以改为使用GSL并使用一些混合物final_act.随你.
理想情况下,我想写一些类似于:
int main()
{
auto blah = foo::init();
}
Run Code Online (Sandbox Code Playgroud)
如果您希望这样做,您可以获取对象的引用.或者忽略它,或者其他什么.我的直接想法是:简单,这只是梅耶的单身人士伪装.从而:
struct foo
{
//...
static bar& init() { static bar b; return b; } …Run Code Online (Sandbox Code Playgroud) 我是redis的新手,我有一个包含数百万个成员ID,电子邮件和用户名的数据集,我正在考虑将它们存储在例如列表结构中.我认为list并且sorted set可能最适合我的情况.
现在,我使用用户名的第一个字母索引到列表并将数据推送到后面列表:rpush list:name:a username,member_id.但是,由于列表未排序,检索数百万条目中的某条记录会变慢吗?
在这种情况下,排序集(因为它已排序)是否优于列表?或者,您是否有其他建议可以提高性能?
访问记录的关键应该是用户名和电子邮件.
std::function已知存在性能问题,因为它可能会进行堆分配。承认,如果您是 100% 诚实的,那么在大多数情况下,一个堆分配应该几乎不是问题……但是让我们假设在特定情况下进行堆分配是不可取的或禁止的。也许我们正在做几百万次回调并且不想要几百万次堆分配,无论如何。
所以......我们想避免堆分配。
Dobbs 博士的文章Efficient Use of Lambda Expressions 和 std::function给出了std::function通过利用标准推荐并在每个主流标准库中实现的小对象优化来优化使用的建议。
这篇文章详细解释了标准库必须如何复制函子,因为std::function对象可能比原始函子的寿命长(尽管std::ref如果你确定它没有,你可以使用),这将是一个糟糕的魔力。此外,需要复制捕获,这是问题:事先不知道闭包的确切类型(或其大小),因为它可能是具有任意数量捕获的任何类型的闭包,因此必须做出一些妥协。达到特定大小时,捕获将保存在function对象内的存储中,超出此大小将动态分配。存储空间很小,从 12 到 16 字节不等,因此假设是 64 位构建,最多有两个指针(不包括实际的函数指针)。
因此,Dobbs 博士建议(并且其他几个站点都采纳了该建议,似乎没有太多反对意见)捕获对结构的引用,该结构包含对您实际想要捕获的内容的引用。这样,您只捕获一个引用,这是完美的,因为它始终适合小对象存储。
这是如何运作的?首先需要复制东西的假设是function对象可能比原始闭包的作用域更长。当然,这意味着它也比它持有引用的结构以及从该结构内部引用的任何内容的生命周期更长。
这应该如何工作?既然我看不到它是如何工作的,有没有更好的知名配方来解决这个问题?(一个不引用无效对象的对象)
考虑到时间限制,我需要处理数十万个事件(产生结果).时钟实际上正在滴答作响,当计时器触发时,必须刷新在该点完成的任何操作.
那个时间没准备好的东西要么被丢弃(取决于重要性度量),要么在下一个时间量程期间处理(具有"重要性提升",即向重要性度量添加常量).
理想情况下,CPU比需要的速度快得多,并且整个集合在时间片结束之前已经准备好了很长时间.不幸的是,世界很少是理想的,在您知道之前,"数十万"变成"数千万".
事件在它们进入时被添加到队列的后面(实际上是一个向量),并且在相应的下一个量程期间从前面处理(因此程序总是处理最后一个量子的输入).
但是,并非所有事件都同样重要.如果可用时间不够,最好放弃不重要的事件而不是重要的事件(这不是一个严格的要求,因为重要的事件将被复制到下一个时间量子的队列,但这样做会进一步增加负载所以它不是一个完美的解决方案).
当然,使用的显而易见的事情是优先级队列/堆.不幸的是,堆积100k元素并不是一个自由操作(或并行),然后我最终将对象放在一些非显而易见且不一定是缓存友好的内存位置,并且从优先级队列中提取元素不会很好地并行化.
我真正喜欢的有点像一个被排序或至少"稍微近似排序"的矢量,之后可以顺序遍历.这将简单地允许我创建例如12个线程(或任何其他数字,每个CPU一个),每个线程处理例如1/64的范围(或另一个大小),从前端到末端缓慢前进,并最终丢弃/推迟遗留下来的东西 - 这将是可以丢弃的重要事件.
简单地使用整个范围进行排序std::sort将是最简单,最直接的解决方案.但是,对项目进行排序所需的时间减少了在固定时间预算内实际处理元素的可用时间,并且排序时间大部分是单CPU时间(并行排序也不是那么好).
此外,进行完美排序(实际上并不需要)可能会带来最坏的情况复杂性,而理想情况下,近似排序应该在最佳状态下执行,并且具有非常可预测的成本.
所以,我正在寻找的是一种仅对数组/向量进行近似排序,但速度快,并且具有可预测(或保证)运行时的方法.
排序键是一个通常在10到1000之间的小整数.被推迟到下一次量子可能会增加("优先级提升")该值的少量,例如100或200.
在一个不同的问题,其中人都应该使用"主观比较"做一个大致的排序(?)希尔排序中提出的.在各种排序演示applet上,似乎至少对于那些典型的"随机随机"输入,shell排序确实可以进行"近似排序",对于数据的3-4次传递看起来并不太糟糕(和至少读取抽头是严格顺序的).不幸的是,选择能够很好地工作的间隙值似乎是一种黑色艺术,而运行时估计似乎也涉及大量调查水晶球.
具有相对大的收缩因子(例如2或3?)的梳子排序看起来也很诱人,因为它严格按顺序访问内存(在两个水龙头上)并且能够快速远离元素远距离.再次,从排序演示小程序判断,似乎3-4遍已经给出了相当合理的"近似排序".
考虑到MSD基数排序,虽然我不确定它如何在典型的16/32位整数中执行,其中大多数最重要的位都是零!人们可能不得不做一个初始传递来找到整个集合中最重要的位,然后是2-3个实际的排序传递?
有没有更好的算法或着名的工作方法与我提到的算法之一?
如何转发可能是rvalue及其(可变参数)参数的可调用对象,以便对待生成的线程100%正确且可靠?
我的猜测是答案是"等待条件变量",但我想确定.
我有一个homebrewn线程实现,几十年来可靠地工作,很久以前std::thread就存在了.它仍然可以正常工作.现在我们确实有std::thread一段时间(或多或少,那就是......由于依赖于gthr/pthreads,MinGW类型的发行版支持线程并不是很好,遗憾的是,我绝对需要支持Win32).
std::thread有这个很酷的功能,你可以传递一个lambda,以及任意参数,它不知何故只是工作.棒极了.
我的实现要求你从一个基类派生,或者传递一个指向状态块的指针,该状态块包含一个函数指针和几个数据指针(基本上与lambda相同,但是丑陋,笨拙,灵活性较差) .
我真的不需要lambda功能,但它很酷,所以我想我只是实现它.这有多难.
代码很简单,除了没有之外,它的效果非常好.我发现在使用内联lambda创建两个线程的许多成功运行后它不起作用.换一种说法
class thread { [...] template<typename F, typename... A> thread(F&& f, A&&... args) : handle( detail::spawn_thread(std::forward<>(...)) ) { } };
thread a([](){...}); // works fine 100% of the time alone, but
thread b([](){...}); // one failure out of 20, if both are present
Run Code Online (Sandbox Code Playgroud)
嗯,这很有趣.怎么会这样?甚至没有足够的代码可能会出现严重故障.转发通用引用,使用指向params的指针生成线程,一切看起来都是完全无辜的.
除此之外,还有不同的,如果其他线程还没有被时间启动spawn_thread返回(这显然发生在20倍左右,一旦我的系统上).因为在这种情况下,新线程将尝试读取您刚刚发布和覆盖的状态.
让我们看看标准库是如何做到的!
有趣的是,看看标准实现(我的无线程可用MinGW-W64上缺少gthr文件,但它们可以在github上找到),事实证明它们几乎完全相同的代码.除了我使用没有下划线和更少typedef的单字符模板参数,标准库使用动态分配.
哦等等,动态分配状态,就是这样!多么血腥明显.让我们作弊,看看他们究竟在做什么.(我编写了代码以使其更易于阅读,删除错误检查和模糊typedef,功能相同).
class thread
{
...
struct _State { virtual …Run Code Online (Sandbox Code Playgroud) 注意:为澄清起见,问题不是restrict一般地使用关键字,而是具体地将关键字应用于此处所述的成员函数。
gcc允许您在成员函数上使用__restrict__(相当于C99的GNU ++ restrict)限定符,从而有效地this在函数范围内创建了限定限定的指针。牛肉在哪里?
大多数成员函数上的其他成员的工作,通过访问它们this,这是一个T* const(并且通常非混淆)。为了this可能被别名,在成员函数内将需要使用第二个指向类型的指针,并且它必须来自某个地方。
这是非成员函数经常发生的情况,例如所有二进制运算符或采用至少两个相同或非平凡类型的指针或引用的其他自由函数。但是,这些函数没有this,因此它们不相关。
赋值运算符,拷贝构造,和一元比较运算符,其中的成员函数的实例this 可以 在原则上被混叠(因为另一个目的通过引用传递)。因此,给它们分配一个限制限定符才是真正有意义的-编译器应该已经清楚所有其他函数仍然具有限制属性(因为永远不会有第二个指向T的指针)。
现在,例如,如果你用restrict的operator=你应该必然不检查所有自赋值,因为你说this是不是该函数的范围内的别名(以及如果这是真的,没有自我的分配也可能会发生)。
显然,这是您可能无法事先知道的,也是没有意义的。
那么,在一种情况下,人们实际上想给成员函数一个限制限定符,并且有意义吗?
今天早上我偶然发现了一些令人惊讶的页面错误,我没想到它们.是的,我可能不应该担心,但它仍然让我感到奇怪,因为在我的理解中它们不应该发生.并且,如果他们不这样做,我会更好.
该应用程序(在WinXP Pro 32位下)保留较大的区域(1GB)的地址空间,VirtualAlloc(MEM_RESERVE)然后分配中等大块(20-50MB)的内存VirtualAlloc(MEM_COMMIT).这是在工人提前完成的,目的是尽可能少地停止主线程.显然,除非内存区域当前被锁定,否则您无法确保不会发生页面错误,但其中一些肯定是可以容忍的(并且是不可避免的).令人惊讶的是每一页都有错误.总是.
因此,假设系统在分配页面之后只是懒惰地创建页面,这在某种程度上也是有意义的(尽管文档提出了不同的东西).很公平,我的坏.
因此,显而易见的解决方法是VirtualLock/ VirtualUnlock,它强制系统创建这些页面,因为它们必须在VirtualLock返回后存在.令人惊讶的是,仍然每一页都有故障.
所以我写了一个小测试程序,按顺序执行上述所有步骤,在每个步骤之间休息5秒,以排除其他代码中的错误.结果是:
MEM_RESERVE 1GB --->成功,零CPU,零时间,没有任何反应MEM_COMMIT 1 GB --->成功,零CPU,零时间,工作集增加2MB,512页错误(每页用户空间分配8个字节的元数据)for(... += 128kB) { VirtualLock(128kB); VirtualUnlock(128kB); } --->成功,零CPU,零时间,没有任何反应for(... += 4096) *addr = 0;---> 262144页面错误,大约0.25秒(内核时间约为95%).Process Explorer内的"工作集"和"物理"增加1GBVirtualFree --->零CPU,零时间,"工作集"和"物理"瞬间变为*poof*.我的期望是,由于每个页面都被锁定一次,因此至少在此之后它必须存在.当超出配额时,它当然可以移入和移出WS(只要有足够的RAM可用,只需更改一个引用).然而,执行时间,工作集和物理内存指标似乎都不支持这一点.相反,正如它所看到的那样,每个单个访问页面都是在故障时创建的,即使它之前已被锁定.当然我可以在工作线程中手动触摸每一页,但是必须有更清洁的方法吗?
我是否VirtualLock 应该做一个错误的假设,或者我不了解虚拟内存的某些内容?任何关于如何以"干净,合法,有效"的方式告诉操作系统我想要记忆的想法,我会想要它真实吗?
更新:
为了回应Harry Johnston的建议,我尝试了实际调用VirtualLock一块GB内存的有点问题的方法.对于这个成功,你必须首先设置进程的相应工作集大小,因为默认配额是200K/1M,这意味着VirtualLock不可能锁定大于200K(或者更确切地说,它不能超过200K锁定一个区域产品总数,以及减去I/O已锁定的内容或其他原因).
设置最小工作集大小为1GB且最大为2GB后,所有页面错误都会在VirtualAlloc(MEM_COMMIT)调用时发生.Process Explorer中的"虚拟大小"立即跳起1GB.到目前为止,它看起来非常非常好.
然而,仔细观察,"物理"仍然保持原样,实际记忆实际上只在您触摸它的那一刻使用.
VirtualLock仍然是一个无操作(故障明智),但提高最低工作集大小样了更接近球门.
但是,篡改WS大小有两个问题.首先,你通常不打算在一个进程中拥有一个千兆字节的最小工作集,因为操作系统会努力保持锁定的内存量.这在我的情况下是可以接受的(它实际上或多或少只是我要求的).
更大的问题是 …
我正在寻找一个SQL语句,它只返回我的表的行,其中的Name字段包含特殊字符(不包括下划线).
我试过了:
SELECT * FROM 'table' WHERE Name REGEXP '^[!#$%&()*+,\-./:;<=>?@[\\\]^`{|}~]+$'
Run Code Online (Sandbox Code Playgroud)
但是没有骰子,这会返回一个空结果集(尽管我专门添加了包含%, $, and #字符的Name字段的行).