Edimetia3D

Edimetia3D

布道

IEEE 754 的 inf 比较问题

首先上结论: 当涉及浮点数比较时,一定要考虑比较符号两侧都是inf的情况. 原因: inf==inf,inf<=inf,inf>=inf 这三个比较都为真(-inf同理),而这种结果可能与我们的期望不符. 解决方法: 1. 如果为真是可以接受的,那么直接使用比较运算符,例如a<=b 2. 如果为真是不可以接受的,那么应当使用作差,例如(a-b)<=0, 这种情况下,当a和b都为inf时,inf之间的运算会输出NaN,从而导致比较结果为false 例如,我有这样一个应用场景: 有射线R和两个平面S0及S1,我们需要求射线R与平面S0的交点p0,以及射线R与平面S1的交点P1. 且要求p0不能比p1离射线起点更远(可以重合) 假如我们用直线的参数方程来描述交点,显然,上面的目标很容易用 t0<=t1 来描述. 此时就可能出现 inf<

By Edimetia3D

记录

KD树与SKD树

KD树与SKD树 首先给出两个搜到的有点内容的KD树文章,论述的比我说的更完整(更冗长),可以先看,也可以看完本文再看. * https://www.zybuluo.com/l1ll5/note/967681 * http://www.whudj.cn/?p=920 主体思想 * KD树和SKD树都使用坐标轴对齐的最小包围盒来描述空间. * 例如,平面内,一堆点的点集对应的空间可以用点A=(min(all_x),min(all_y)),B=(max(all_x),max(all_y)) 对应的矩形空间来描述. 当点的个数变为1时,这个矩形空间也会自然地退化为一个点. * 构建时的主要思想: 每个节点node都对应了一个空间box(node),node->plane用一个超平面把这个空间box(node)一分为二,记为sub_left,

By Edimetia3D

记录

设计模式

For C/C++ user 很多设计模式相关的资料都是用Java来描述的,有必要简单补充一下Java和C++在OOP技术层面上的区别 * Java不支持任何形式的运算符重载 * Java明确区分接口和类,类只能从一个类派生,但是一个类可以实现多个接口 * 在Java中,所有方法默认是虚(virtual)的 * 对CPP而言,Java风格的接口可以视为一个只有pure virtual成员函数的基类,称为Interface * implement,is-a(inherit),has-a * implement: 特指继承Interface,并通过override实现其中函数的行为. * is-a: 特指继承普通类后,普通类和基类的关系. * has-a: 特指持有某个对象. 杂谈 * 设计模式可以说就是各种各样的"OOP最佳实践方法". 一个设计模式对应了一种组织代码的风格,对应了一种解决问题的策略. * 设计模式可以说是程序员的"行话",使用"行话"有利于交流,但是并不一定有利于问题的解决,简单优雅的解决问题总是

By Edimetia3D

C++系列

SomeCpp

零碎知识点 * fflush仅仅是为了输出而设计的, 标准中并没有说明它对输入缓冲的效果. * 一元运算符和=是右结合的,这和<<是完全不同的,a=b=c意味着a=(b=c),b=c将先执行,而a<<b<<c则是(a<<b)<<c,a<<b将先执行. * C++11后引入了thread_local型的生命周期,这种对象和线程的生命周期是一致的 * C++11中很多类型都支持列表初始化,a = {value1,value2...} * 列表初始化会额外检测是否可能存在信息丢失,如果可能存在丢失,则无法通过编译期检查. * 对于自定义类,支持列表初始化意味着存在这样的ClassName(initializer_list&

By Edimetia3D

C++系列

Some Multi Thread

C++标准库提供的 mutex 在大部分场合都足以保证线程安全, 但是当问题变得更加极端时,就可能需要使用lockfree风格的并行编程了. 而为了正确实现lockfree, 你将打开一扇新的大门, 接下来的名词都是在学习过程中必须正确理解的: memory model, reordering, weak(relax), strong(strict), fence, barrier, release, acquire, seq_cst, consume, mutex, futex, lockfree(lockless), synchronize-with, happens-before, ABA, DCLP, 背景 在单核时代,CPU设计中引入了很多特性,其中很重要的一点就是乱序执行,乱序执行的基本原则是:乱序执行的最终效果应当和顺序执行一致,这个原则在单线程下是比较容易保证的.例如,对于下面的代码,先写入a还是先写入b都不影响后序的指令执行的正确性,所以编译器及硬件都可以自行选择先执行哪一个. a = 8; b = 9; 当进入并行环境之后,乱序执行的基本原

By Edimetia3D

布道

Python for C++ Programner

这里谈一下个人的学习建议. 首先可以阅读官方的入门教程, 看完这一部分, 对于一个熟练的C++程序员, 应该可以凑合写出可堪一用的代码了. 对于大部分不以Python为主要工作语言的开发者,到此基本就足够了. 如果有时间,我建议直接阅读Python in a Nutshell第七章之前的内容(不含第七章),并不用完全看懂,大部分细节也不用去记忆,只需要看完即可,至此,你就能基本了解Python的运行机制, 写出质量稳定可控(不会存在低级错误)的代码了. 上面两步完成后, 对一个熟悉C++的程序员而言, 基本任何Level的Python资料都可以看了. 你可以继续看Python in a nutshell中感兴趣的部分,也可以选择Fluent Python. 在有相当多的开发经验之后,可以阅读Python Cookbook. 如果仍然想进一步深入, 那么你应该直接学习CPython解释器的实现,Python Developer’s Guide可以作为一个入口. 最后,本文仅仅简单扼要的说明了Python和C++不同的一些特性, 可以作为补充阅读. 书评

By Edimetia3D

C++系列

[Cpp基础][09]C++11多线程编程基础

C++11为多线程开发准备了一套标准的基础设施,主要为<thread>,<mutex>,<condition_variable>, 这套组件基本是"pthread"的标准化.本文主要介绍C++11多线程开发相关的基础内容.如果需要更多的细节,可以直接google或者查手册进行了解. 可调用对象 可调用对象在C++ 11中是非常重要的概念, 它使得"函数"变得更加像对象. 线程库完整的支持可调用对象. * 支持()运算符的对象都是可调用对象,这些工具的设计比较独立,可以在使用时再查reference,常见的有 * bind创建的对象 * lambda * 重载了()的类 * 函数/函数指针 * function<T>. std::thread * 标准库提供了std::thread来进行基础的线程管理,

By Edimetia3D

C++系列

C++ OOP编程综述

嵌套类和局部类 * 定义在类X内的类Y称为嵌套类,它就是一个普通类,只不过使用的作用域被限制了. * 定义在函数内的类Y称为局部类,这种类限制很多,主要用于在语言层面支持Lambda,实践中基本不用. struct(class)的内存布局 * C++的struct和class实例大小不会为0,即便它内部没有任何数据变量.主要是因为编译器总是需要为实例分配内存,使得对象能获得有效的地址,且不同对象的地址总应该是不同的. * 类型布局相关的名词有很多,如POD,Aggragate,naive等,具体我也不是很清楚,总之很麻烦. * 如果需要把sturct或class对象通过C风格直接从内存层面管理(如memcpy),那么要求它的内存布局是平凡的. * 只要类型涉及到virtual, 那类型实例的首地址存储的一定是vptr, 涉及virtual只需满足任意一个条件: * 直接或间接使用虚继承 * 直接或间接使用虚函数 一般规则 C++对象的内存布局对于理解多继承/虚继承非常重要, 基本要关注的有三点 1

By Edimetia3D

C++系列

[Cpp基础][11]"异常"

异常 * C++内所说的异常是指:可以预见的非正常状况,例如输入的指针为空;而非不可预见的问题,例如突然停电,或者突然被用户把进程kill掉,并不是C++需要处理的"异常" * 异常特性会导致程序的执行流程不可控,且往往对OS及runtime有一定的要求(可移植性差),所以没有特殊需求时,不应当使用这个特性. * throw-try-catch是异常系统的典型三个环节. * throw出的可以是任意对象,只要catch处声明的对象可以用throw的对象初始化即可.习惯上我们会专门设计一个类,因为自定义类可以承载更多的信息 * 异常catch中的形参可以使用引用,以使用多态机制 * 异常抛出后寻找catch的过程称为栈展开,被展开的函数栈内所有局部对象都将被销毁,因此抛出的异常对象必须不依赖局部对象. * 标准库内提供了以exception为基类的若干异常,我们可以使用这个类,也可以自定义类,该类的const char * what()成员用于给用户提供信息. * catch时,优先使用引用, 从而保证能派生类实例能绑定到基类参数上

By Edimetia3D

C++系列

[Cpp基础][10]重载运算符

重载运算符 规定 * 赋值,取下标,调用,箭头,类型转换,这些运算符只能作为成员函数. * 用户重载的&&与||不会进行短路求值. 习惯 * 重载主要分为全局重载和类内重载,一般而言,二元运算都应该在全局重载(顺序问题). * 改变对象状态的运算符一般应当设为成员函数,拥有对称性的运算符一般应在类外重载. * 从技术层面说,重载运算符的参数可以是指针类型的,但是这一般与我们使用语言的习惯不符,所以形参类型最好只是T或T&,而不要是指针. * 定义有关联的重载运算符时一定要考虑兼容性,例如a<b为假,a>b也为假,那么a==b就应该返回真. * 重载中应当尽可能的保持语义与内置风格一致. * 例如,如果重载了++运算符,那么应当保证++x和x+=1及x=x+1有同样的效果. * 尽量不要重载全局的operator new,仅在类内重载它. * 类内重载的new和delete都是static的,因此,无法使用this相关的量

By Edimetia3D