Home Php C# Sql C C++ Javascript Python Java Go Android Git Linux Asp.net Django .net Node.js Ios Xcode Cocoa Iphone Mysql Tomcat Mongodb Bash Objective-c Scala Visual-studio Apache Elasticsearch Jar Eclipse Jquery Ruby-on-rails Ruby Rubygems Android-studio Spring Lua Sqlite Emacs Ubuntu Perl Docker Swift Amazon-web-services Svn Html Ajax Xml Java-ee Maven Intellij-idea Rvm Macos Unix Css Ipad Postgresql Css3 Json Windows-server Vue.js Typescript Oracle Hibernate Internet-explorer Github Tensorflow Laravel Symfony Redis Html5 Google-app-engine Nginx Firefox Sqlalchemy Lucene Erlang Flask Vim Solr Webview Facebook Zend-framework Virtualenv Nosql Ide Twitter Safari Flutter Bundle Phonegap Centos Sphinx Actionscript Tornado Register | Login | Edit Tags | New Questions | 繁体 | 简体


10 questions online user: 6

9
votes
answers
58 views
+10

为什么C和Java圆形浮点数不同?

考虑浮点数0.644696875让我们使用Java和C将其转换为八位小数的字符串:

Java
  import java.lang.Math; public class RoundExample {public static void main(String [] args){System.out.println(String.format(“%10.8f”,0.644696875)); }   

结果:0.6446968 8

自己尝试一下: http://tpcg.io/oszC0w

C
  #include&lt; stdio.h&gt; int main(){printf(“%10.8f”,0.644696875); // double to string return 0; }   < 结果:0.6446968  7   

亲自尝试: http:// tpcg .io / fQqSRF

问题

为什么最后一位数字不同?

背景

数字0.644696875不能完全表示为机器编号。它表示为分数2903456606016923/4503599627370496,其值为0.6446968749999999

这无疑是一个边缘情况。但我对这种差异的根源非常好奇。

相关: HTTPS://mathematica.stackexchange。

沙发
+60

可能这里发生的事情是他们使用稍微不同的方法将数字转换为字符串,这引入了舍入错误。在编译期间将字符串转换为浮点数的方法也可能在它们之间是不同的,由于舍入,这也可能会给出稍微不同的值。

请记住,float具有24位精度对于它的分数,它出现在~7.22十进制数[log10(2)* 24],并且它们之间的前七个数字一致,所以它只是最后几个不同的最低有效位。

欢迎来到浮点数学的有趣世界,其中2 + 2并不总是等于4。

什么是.22的十进制数字? - JL2210 6小时前

@ JL2210在浮点项中,一个非常不准确的表示将在~2.2个不同的值而不是正常值10之间徘徊,换句话说,它只有22%准确,而不是100%。 - tadman 5小时前

没有涉及浮点(32位二进制浮点)。如果有的话,该值将为0.644696891307830810546875,我们会看到“0.64469689” - 在9中结束,而不是8或7. - Eric Postpischil 4小时前

板凳
+30

结论

在这种情况下,Java规范需要麻烦的双舍入。0.6446968749999999470645661858725361526012420654296875首先转换为0.644696875然后四舍五入为0.64469688。

相比之下,C实现简单地将0.6446968749999999470645661858725361526012420654296875直接舍入到八位数,产生0.64469687。

预备

对于 Double ,Java使用IEEE-754基本64位二进制浮点。在这种格式中,最接近源文本中的数字的值0.644696875是0.6446968749999999470645661858725361526012420654296875,我相信这是用 String.format(“%10.8f”,0.644696875)格式化的实际值 1 < / p>

Java规范说的是什么

使用 Double 类型和 f 格式进行格式化的文档说:

如果精度小于 Float.toString(float) Double.toString返回的字符串中小数点后面的数字位数(分别为double),然后使用round half up算法对值进行舍入。否则,可以附加零以达到精度

让我们考虑“ Double返回的字符串。的toString(双)”。对于数字0.6446968749999999470645661858725361526012420654296875,此字符串为“0.644696875”。这是因为Java规范说 toString 只生成足够的十进制数字来唯一地区分集合中的数字。 Double ,“0.644696875”在这种情况下只有足够的数字。 2

该数字在小数点后有九位数,“%10.8f”请求八个,所以上面引用的段落说“值”四舍五入。它是什么意思 - format 的实际操作数,即0.6446968749999999470645661858725361526012420654296875,或者它提到的那个字符串,“0.644696875”?由于后者不是数值,我原以为“价值”意味着前者。但是,第二句说“否则[也就是说,如果请求更多位数]”,则可以附加“如果我们使用 format 的实际操作数,我们将显示其数字,而不是使用零。但是,如果我们将字符串作为数值,其十进制表示在其中显示的数字后将只有零。所以这似乎是解释的目的,Java实现似乎符合这一点。

因此,要使用“%10.8f”格式化此数字,我们首先将其转换为0.644696875,然后使用圆形半升规则将其舍入,产生0.64469688。

这是一个错误的规范,因为:

  • 它需要两次舍入,这会增加错误。
  • 舍入发生在难以预测和难以控制的地方。某些值将在两位小数后舍入。一些程序将在13之后进行舍入。程序无法轻易预测或调整它。

    (另外,很遗憾他们写了“可能”附加了零。为什么不“否则,”附加零 以达到精度。“使用”may“,看起来他们正在给实现选择,虽然我怀疑他们的意思是”可能“是根据是否需要零到达精度,而不是实现者是否选择附加它们。)

    脚注

    1 0.644696875 在源文本中转换为 Double ,我相信结果应该是 Double 格式中可表示的最近值。(我没有在Java文档中找到它,但它符合要求实现行为相同的Java理念,我怀疑转换是按照 Double.valueOf(String s)完成的, 确实需要这个。)最近的 Double 到0.644696875是0.6446968749999999470645661858725361526012420654296875。

    2 数字越少,七 - 数字0。64469687不足,因为最接近它的 Double 值为0.6446968 699999999774519210404832847416400909423828125 因此需要八位数来唯一地区分0.6446968 749999999470645661858725361526012420654296875

8
votes
answers
34 views
+10

在C ++头文件中使用指令的位置

对于我的项目,我使用了一些非常复杂的数据结构,例如

  std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt;   

为了便于阅读,我想声明类型别名。我构建项目的代码已经通过在头文件中全局放置使用语句来实现这一点:

  / / bar.h #ifndef BAR_H #define BAR_H #include&lt; unordered_map&gt; #include&lt; list&gt; #include&lt; memory&gt; #include“foo.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt ;; class Bar {FooTable create_foo(); }; #endif   

由于我的C ++知识有点生疏,我只是采用了这种风格 - 但现在我读到使用使用以这种方式可能会有问题,因为它强制包含这个标题的所有内容。

尽管有大量的谷歌搜索,我找不到如何正确处理这个问题的具体答案,只有很多关于不该做的事情的陈述。所以,我只是把使用放在类中:

  // bar.h #ifndef BAR_H #define BAR_H #include&lt; unordered_map&gt; #include&lt; list&gt; #include&lt; memory&gt; #include“foo.h”class Bar {using FooTable = std :: unordered_map&lt; int,std :: list&lt; std::shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable create_foo(); }; #endif   

然而,这有一个缺点,我需要在源文件中重述别名:

  // bar.cpp #include“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable Bar :: create_foo(){...}   

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable create_foo(); }; #endif

然而,这有一个缺点,我需要在源文件中重述别名:

  // bar.cpp #include“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable Bar :: create_foo(){...}   

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable create_foo(); }; #endif

然而,这有一个缺点,我需要在源文件中重述别名:

  // bar.cpp #include“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable Bar :: create_foo(){...}   

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? const Foo&gt;&gt;&gt ;; FooTable create_foo(); }; #endif

然而,这有一个缺点,我需要在源文件中重述别名:

  // bar.cpp #include“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable Bar :: create_foo(){...}   

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? const Foo&gt;&gt;&gt ;; FooTable create_foo(); }; #endif

然而,这有一个缺点,我需要在源文件中重述别名:

  // bar.cpp #include“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable Bar :: create_foo(){...}   

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? FooTable create_foo(); }; #endif

然而,这有一个缺点,我需要在源文件中重述别名:

  // bar.cpp #include“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable Bar :: create_foo(){...}   

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? FooTable create_foo(); }; #endif

然而,这有一个缺点,我需要在源文件中重述别名:

  // bar.cpp #include“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable Bar :: create_foo(){...}   

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? / pre>

但是这有一个缺点,我需要在源文件中重述别名:

  // bar.cpp#包括“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable Bar :: create_foo(){...}   

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? / pre>

但是这有一个缺点,我需要在源文件中重述别名:

  // bar.cpp#包括“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt;&gt;&gt ;; FooTable Bar :: create_foo(){...}   

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? pre class =“lang-cpp prettyprint-override”> // bar.cpp #include“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt; &GT;取代; FooTable Bar :: create_foo(){...}

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? pre class =“lang-cpp prettyprint-override”> // bar.cpp #include“bar.h”使用FooTable = std :: unordered_map&lt; int,std :: list&lt; std :: shared_ptr&lt; const Foo&gt; &GT;取代; FooTable Bar :: create_foo(){...}

虽然这似乎有用,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? create_foo(){...}

虽然这似乎有效,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名? create_foo(){...}

虽然这似乎有效,但我不确定这是否安全......我的直觉告诉我它有点难看。所以在我重写整个项目之前,我想我会问:是否有更好/更优雅/更安全的方法来做到这一点?或者我应该完全避免在头文件中使用类型别名?

沙发
+50
+50

然而,这有一个缺点,我需要在源文件中重述别名:

这是不正确的。你只需要使它 public 然后指定适当的范围,所以你在 Bar 范围之外调用 Bar :: FooTable (其中包括返回类型,除非尾随!):

  Bar :: FooTable Bar :: create_foo(){/ * ... * /}   

  auto Bar :: create_foo() - &gt; FooTable {/ * ... * /}   

(只需 FooTable 就可以了 这个定义,因为它是一个会员!)

你的方法很好,虽然我也把所有内容放在命名空间中。那么你的别名是否在课堂上并不重要:它仍然是你自己的代码中的自包含。它纯粹是一种风格问题,对其他任何人都没什么影响。

+20

但现在我读到使用这种方式使用可能会有问题,因为它会强制包含此标题的所有内容。

此问题同样适用于您定义的class Bar 包含此标头的所有程序都必须使用 Bar 的此定义。

所以,我只是把使用放在类中

你减少了全局命名空间中的声明数量。这很好。

但是这有一个缺点,我需要在源文件中重新设置别名

这是不必要的。

如果您将别名公之于众,您可以使用范围解析运算符将其引用为 Bar :: FooTable 或者您可以使用尾随返回类型,其中在类的范围内查找上下文名称:

  auto Bar :: create_foo() - &gt; FooTable   

有一个更通用的解决方案:命名空间。将所有自己的声明放入单个命名空间(可以进一步划分为子命名空间)。这样,您只需在全局命名空间中引入一个名称,这可以大大减少名称冲突的可能性。

在C ++头文件中使用指令的位置

相同推理适用于您放置任何其他声明的地方。至少进入你自己的命名空间,但通常将声明放在一个狭窄的范围内就足够了,这是一个不错的经验法则。如果类型别名仅用于那个类,那么成员类型别名很有意义。

+10

正如评论中已经提到的,您无需重新声明它。如果在类中声明它,只需使用 Bar :: FooTable 来引用它。如果您在命名空间中声明它,那就是一样的,除非您在命名空间之外使用命名空间名称。如果你使用typedef也是一样的。

无论是在命名空间还是在类中声明它都完全取决于您。就个人而言,我尽量确保其范围尽可能相关。例如,如果我有一个仅用于连接特定类的typedef,我将typedef放在类中。如果它具有与特定类无关的全局值,我将其声明在命名空间中。

话虽如此,我建议你不要 t在全局命名空间中声明它以避免歧义如果你出于某种原因发现自己有一个命名冲突,如果你最终得到一个不同的typedef(或者我认为其他一般与你的typedef / using语句同名)在某处声明另外,

此外,类中的typedef受访问修饰符的限制。默认情况下,它是私有的,这意味着你不能在课外使用它。如果您打算这样做,您需要将其公之于众。

在安全性方面,在全局范围内声明它并不是特别安全,特别是如果将它与 using namespace 结合使用(这可能是它自己的问题 - 请参阅< a href =“https://stackoverflow.com/a/1452738/6296561”>这个)。您可以在自己的命名空间中声明它( 命名空间Baz {使用FooTable = blah; / *更多代码* /} ),但声明它是一个类会产生相同的效果。

请注意,名称空间和类本质上是作用域,它们有自己的动态。如果在命名空间Baz 中的源文件中编写代码,则可以访问在同一命名空间中声明的typedef,而不指定 Baz :: FooTable 它本质上暴露了typedef,类似于它在全局命名空间中的工作方式,但是以更受限制的方式。有关此处的更多信息。

请注意,名称空间和类本质上是作用域,它们有自己的动态。如果在命名空间Baz 中的源文件中编写代码,则可以访问在同一命名空间中声明的typedef,而不指定 Baz :: FooTable 它本质上暴露了typedef,类似于它在全局命名空间中的工作方式,但是以更受限制的方式。有关此处的更多信息。

请注意,名称空间和类本质上是作用域,它们有自己的动态。如果在命名空间Baz 中的源文件中编写代码,则可以访问在同一命名空间中声明的typedef,而不指定 Baz :: FooTable 它本质上暴露了typedef,类似于它在全局命名空间中的工作方式,但是以更受限制的方式。有关此处的更多信息。 您可以访问在同一名称空间中声明的typedef,而无需指定 Baz :: FooTable 它本质上暴露了typedef,类似于它在全局命名空间中的工作方式,但是以更受限制的方式。有关此处的更多信息。 您可以访问在同一名称空间中声明的typedef,而无需指定 Baz :: FooTable 它本质上暴露了typedef,类似于它在全局命名空间中的工作方式,但是以更受限制的方式。有关此处的更多信息。

10
votes
answers
24 views
+10

为什么这个C ++折叠表达式有效?

cppreference 上,我看到有四种类型的折叠表达式,一元右,一元左,二元右,二元左。这个折叠表达式的类型是什么?我很难理解为什么它有效。

  template&lt; typename Res,typename ... Ts&gt; 矢量&lt; RES&GT; to_vector(Ts&amp; ... ts){vector&lt; Res&gt; VEC; (vec.push_back(ts)...); // *返回vec; }   

行*中“pack”,“op”和“init”的值是多少?

此示例来自Bjarne的第244页Stroustrup的

up vote 10 down vote accepted favorite
沙发
+100
+50

语法无效。它缺少一个逗号:

 (vec.push_back(ts),...)// ^   

因此它是“一元右折” :

 (pack op ...)  

op 是逗号。

13
votes
answers
50 views
+10

为什么在将10000000转换为char时会得到38528?

Java使用32位作为焦点 - 因此最大值为65536。

但是下面的代码给出了标题中报告的结果。

  public static void main(String [] args){int a = 10000000; char b = 33; b =(char)a; 的System.out.println((int)的B); }  
    
        
up vote 10 down vote accepted favorite
沙发
+100
+50

char 是16位,而不是32位。

65535 char 的最大值,<代码> 10000000 大于此值,因此您无法将该值存储在 char 中。

10000000 in binary is 100110001001011010000000

现在当将其转换为 char 时,16位“fit”的剩余部分将被删除,留下 1001011010000000

十进制的二进制 1001011010000000 38528

非常感谢 !我现在明白为什么这段代码给了我这个结果! - Д П. 8月31日23:31

结果我期待65536。 - Д П. 8月31日23:32

我今天开始学习Java,抱歉这个愚蠢的问题:) - Д。П. 8月31日23:33

这不是一个愚蠢的问题,否则你会得到downvotes而不是upvotes。这是一个有效且易于理解的初学者的问题。假设值向下舍入而不是丢弃二进制位是有意义的。继续询问和学习,这就是我们开始的方式。 - Max Vollmer 8月31日23:35

+30

Java使用32位字符

不,Java使用 16 bit char s。

所以最大值是65536。

几乎 - 就 char 的最大值而言,它是 65535 ,但是,2s-complement 32位值的最大值为2 31 ,即 2147483647

但是下面的代码给出了标题中报告的结果。

  int a = 10000000; char b = 33; b =(char)a;    

嗯, 10000000 肯定大于 65535 ,不是吗?在尝试将该数字放入 char 时,您有何期待?你得到的是溢出

“所以最大值是65536”不,最大值是65535. - Andreas 2天前

@Andreas正确,我的疏忽。编辑。 - Fureeish 2天前

11
votes
answers
30 views
+10

C结构如何在程序集中传递给函数?

1)C结构如何在程序集中传递给函数。我的意思是按值传递,而不是通过引用传递。2)顺便说一句,callees如何将结构返回给其来电者?因为我不是母语为英语的人,所以我很抱歉表达不好。

我写了一个简单的程序来证明C结构如何传递给函数。但结果却相当惊人。一些值通过寄存器传递,但是通过将它们推入堆栈来传递一些值。这是代码。

源代码

  #include&lt; stdio.h&gt; typedef struct {int age; enum {男人,女人} gen; 双倍高度; int类; char * name; 学生 void print_student_info(student s){printf(“age:%d,gen:%s,height:%f,name:%s”,s.age,s.gen ==男人?“男人”:“女人”,s.height,s.name); } int main(){学生s; s.age = 10; s.gen =男人; s.height = 1.30; s.class = 3; s.name =“汤姆”; print_student_info(一个或多个); 返回0; }   

asm

  6fa:55 push%rbp 6fb:48 89 e5 mov%rsp,%rbp 6fe:48 83 ec 20 sub $ 0x20, %rsp 702:c7 45 e0 0a 00 00 00 movl $ 0xa,-0x20(%rbp)709:c7 45 e4 00 00 00 00 movl $ 0x0,-0x1c(%rbp)710:f2 0f 10 05 00 01 00 movsd 0x100(%rip),%xmm0#818&lt; _IO_stdin_used + 0x48&gt; 717:00 718:f2 0f 11 45 e8 movsd%xmm0,-0x18(%rbp)71d:c7 45 f0 03 00 00 00 movl $ 0x3,-0x10(%rbp)724:48 8d 05 e5 00 00 00 lea 0xe5(%rip),%rax#810&lt; _IO_stdin_used + 0x40&gt ; 72b:48 89 45 f8 mov%rax,-0x8(%rbp)72f:ff 75 f8 pushq -0x8(%rbp)732:ff 75 f0 pushq -0x10(%rbp)735:ff 75 e8 pushq -0x18(% rbp)738:ff 75 e0 pushq -0x20(%rbp)73b:e8 70 ff ff ff callq 6b0&lt; print_student_info&gt; 740:48 83 c4 20添加$ 0x20,%rsp 744:b8 00 00 00 00 mov $ 0x0,%eax 749:c9 leaveq 74a:c3 retq 74b:0f 1f 44 00 00 nopl 0x0(%rax,%rax,1 )  

我期望结构使用堆栈传递给函数,

沙发
+30
+50

正如其他人所指出的那样 - 在大多数情况下,按价值传递结构通常是不受欢迎的,但仍然可以通过 C 语言来允许。我将讨论您使用的代码,即使它不是我将如何使用它。


如何传递结构取决于ABI / Calling约定。目前有两种主要的64位ABI使用(可能还有其他)。 64位Microsoft ABI x86-64 System V ABI 64位Microsoft ABI很简单,因为按值传递的所有结构都在堆栈中。在x86-64系统中V ABI(由Linux / MacOS / BSD使用)更复杂,因为有一个递归算法用于确定结构是否可以通过通用寄存器/向量寄存器/ X87 FPU的组合传递堆栈寄存器。如果它确定结构可以在寄存器中传递,那么对象不会被放置在堆栈上以便调用函数。如果它不符合规则的寄存器,那么它将被传递到堆栈的内存中。

有一个迹象表明你的代码没有使用64位Microsoft ABI作为32字节的在进行函数调用之前,编译器没有保留阴影空间,所以这几乎肯定是针对x86-64 System V ABI的编译器。整个参数在内存中传递。

恰好是你的结构试图将前两个32位 int 值打包在64中位寄存器和 double 放在向量寄存器中,然后将 int 放在64位寄存器中(由于对齐规则),指针传入另一个64位寄存器位寄存器。您的结构将超过两个8字节(64位)寄存器,而前八字节(64位)寄存器不是SSE寄存器,因此编译器将结构传递给堆栈。

您有未优化的代码,但我们可以将代码分解成块。首先是构建堆栈框架并为局部变量分配空间。如果没有启用优化(这里就是这种情况),结构变量 s 将构建在堆栈上,然后该结构的副本将被压入堆栈以调用 print_student_info

这构建堆栈帧并为局部变量分配32个字节(0x20)(并保持16字节对齐)。自然对齐规则之后,您的结构恰好大小为32字节:

  6fa:55 push%rbp 6fb:48 89 e5 mov%rsp,%rbp 6fe:48 83 ec 20 sub $ 0x20,%rsp   

您的变量< code> s 将从RBP-0x20开始并以RBP-0x01(包括端点)结束。代码构建并初始化堆栈上的 s 变量( student struct)。 age 字段的32位int 0xa(10)位于RBP-0x20结构的开头。 Man 的32位枚举位于RBP-0x1c的字段 gen 中:

  702:c7 45 e0 0a 00 00 00 movl $ 0xa,-0x20(%rbp)709:c7 45 e4 00 00 00 00 movl $ 0x0,-0x1c(%rbp)  

常量值1.30(类型 double )由编译器存储在内存中。使用Intel x86处理器上的一条指令无法从内存移动到内存,因此编译器移动了双值1。30从内存位置RIP + 0x100到向量寄存器 XMM0 然后将 XMM0 的低64位移到RBP堆栈上的 height 字段-0x18:

  710:f2 0f 10 05 00 01 00 movsd 0x100(%rip),%xmm0#818&lt; _IO_stdin_used + 0x48&gt; 717:00 718:f2 0f 11 45 e8 movsd%xmm0,-0x18(%rbp)  

值3放在 class 字段的堆栈中在RBP-0x10:

  71d:c7 45 f0 03 00 00 00 movl $ 0x3,-0x10(%rbp)  

最后是64位字符串 Tom 的地址(在程序的只读数据部分中)被加载到 RAX 然后最终进入RBP-0x08堆栈的 name 字段。虽然 class 的类型只有32位( int 类型),但它被填充为8个字节,因为以下字段 name 必须是由于指针大小为8个字节,因此在8字节边界上自然对齐。

  724:48 8d 05 e5 00 00 00 lea 0xe5(%rip),%rax#810&lt; _IO_stdin_used + 0x40的&GT; 72b:48 89 45 f8 mov%rax,-0x8(%rbp)  

此时我们有一个完全建立在堆栈上的结构。然后编译器通过将结构的所有32个字节(使用4个64位推送)推入堆栈来复制它以进行函数调用:

  72f:ff 75 f8 pushq -0x8(%rbp)732:ff 75 f0 pushq -0x10(%rbp)735:ff 75 e8 pushq -0x18(%rbp)738:ff 75 e0 pushq -0x20(%rbp)73b:e8 70 ff ff ff callq 6b0&lt; print_student_info&gt;   

然后典型的堆栈清理和功能结束:

  740:48 83 c4 20 add $ 0x20,%rsp 744:b8 00 00 00 00 mov $ 0 x0,%eax 749:c9 leaveq   

重要提示:在这种情况下,使用的寄存器不是为了传递参数,而是代码的一部分初始化堆栈上的 s 变量(struct)。


返回结构< / h2>

这也取决于ABI,但在这种情况下我将专注于x86-64 System V ABI,因为这是你的代码所使用的。

按引用:在 RAX 中返回指向结构的指针。返回指向结构的指针是首选。

按值:由值返回的 C 中的结构强制编译器为返回分配额外的空间调用者中的结构,然后该结构的地址作为 RDI 中隐藏的第一个参数传递给函数。被调用函数会将 RDI 中传递的地址作为参数放入 RAX 中作为返回值。从函数返回时, RAX 中的值是指向存储返回结构的地址的指针,该地址始终与隐藏的第一个参数 RDI 中传递的地址相同。ABI在返回值小标题下的 3.2.3参数传递部分讨论了这一点,其中说:

    < li>如果类型具有类MEMORY,则调用者为返回值提供空间,并在%rdi中传递此存储的地址,就好像它是函数的第一个参数一样。实际上,该地址成为“隐藏的”第一个参数。此存储不得通过除此参数之外的其他名称与被调用者可见的任何数据重叠。

非常感谢。你的答案真的解决了我的困惑 - 凯文_xie 19分钟前

@Kevin_xie没问题! - Michael Petch 18分钟前

+20

对于您的问题没有一般性的答案 - 每个编译器的工作方式都不同,并且可以根据您选择的优化方式做不同的事情。您所观察到的是一种常见的优化 - 合适类型的前几个参数在寄存器中传递,并在堆栈上传递额外的和/或复杂的。

此代码未经优化。使用的寄存器是在堆栈上构建s变量(student结构)。在该代码的情况下,根本没有使用寄存器来传递参数。然后将在堆栈上创建的整个结构复制到堆栈上,作为参数传递给函数。 - Michael Petch 10小时前

11
votes
answers
36 views
+10

Task on the number of iterations

There is a number N every iteration it becomes equal to (N*2)-1 I need to find out how many steps the number will be a multiple of the original N;

( 1≤ N ≤ 2 · 10 9 )

For example:

N = 7; count = 0

N_ = 7*2-1 = 13; count = 1; N_ % N != 0

N_ = 13*2-1 = 25; count = 2; N_ % N != 0

N_ = 25*2-1 = 49; count = 3; N_ % N == 0 

Answer is 3

if it is impossible to decompose in this way, then output -1

       #include <iostream> 
       using namespace std;

       int main(){
           int N,M,c;
           cin >> N;
           if (N%2==0) {
               cout << -1;
               return 0;
           }
           M = N*2-1;
           c = 1;
           while (M%N!=0){
               c+=1;
               M=M*2-1;
           }
           cout << c;
           return 0;
       }

It does not fit during (1 second limit). How to optimize the algorithm?

P.S All the answers indicated are optimized, but they don’t fit in 1 second, because you need to change the algorithm in principle. The solution was to use Euler's theorem.

沙发
+50

正如其他答案所暗示的那样,问题等同于找到 c ,使 pow(2,c)= 1 mod N 如果N是偶数,则这是不可能的,否则可能(如您的代码所暗示的那样)。

线性时间方法是:

  int c = 1; uint64_t m = 2; while(m!= 1){c + = 1; m =(2 * m)%N; } printf(“%d”,c);   

要在1秒内解决这个问题,我认为你不能使用线性时间算法。最糟糕的情况是 N 是素数大而且很大。例如1999999817,上面的代码在我的笔记本电脑上运行大约10秒钟。

相反,将 N 纳入其主要因素。求解 2 ^ c = 1 mod p ^ k 对于给定的素数幂,如果 k = 1 ,则解决方案是 c = p-1 k 更大时,细节非常混乱,但你可以在这里找到一个书面解决方案: https://math.stackexchange.com/questions/1863037/discrete-logarithm-modulo-powers-of-a-small-prime 对于给定的素数幂,如果 k = 1 ,则解决方案是 c = p-1 k 更大时,细节非常混乱,但你可以在这里找到一个书面解决方案: https://math.stackexchange.com/questions/1863037/discrete-logarithm-modulo-powers-of-a-small-prime

板凳
+40

问题是你溢出,int数据类型只有32位,溢出2 ^ 31-1,在这个问题你不需要保持M的实际值,你可以保持模数n。

  while(M%N!= 0){c + = 1; M = M * 2-1; M%= N}   

编辑:此外,你实际上不需要超过N次迭代来检查是否存在0 mod,因为N只有N个不同的mod并且它只是骑自行车。因此,如果没有0 mod,你还需要牢记这一点。

如果有溢出,那么测试就没有错误的答案,但我有一个与时间相关的错误 - yoloy 8月29日5:38

这当然是你迈出的一大步,但它并没有增加速度 - yoloy 8月29日5:39

@yoloy你怎么知道法官在收到错误答案之前没有放弃?这可能是也可能不是整个问题,但它是一个错误。 - user4581301 8月29日5:39

旁注:在M%= N的情况下,循环条件中的M%N基本上是冗余的。 - user4581301 8月29日5:40

当你溢出时,while循环不会结束,因为mod不会达到0,数字将变为负数并且继续溢出,这导致超出时间限制 - Malek Aug 29 at 5:42

地板
+20

毫无疑问,您的代码的主要问题是有符号整数溢出

每当 M时,我都会添加 M 的打印件已更改(即 cout&lt;&lt; M&lt;&lt; endl; )并给它输入29.这就是我得到的:

  57 113 225 449 897 1793 3585 7169 14337 28673 57345 114689 229377 458753 917505 1835009 3670017 7340033 14680065 29360129 58720257 117440513 234881025 469762049 939524097 1879048193 -536870911 -1073741823 -2147483647 1 1 1 ...无限循环  

如您所见,您已经签署了整数溢出。这是C中的未定义的行为,所以任何事情都可能发生!在我的机器上,我结束了一个讨厌的无限循环。在考虑性能之前必须先修复它。

简单的解决方法是添加一行,如

  M = M%N;   

每当 M 被更改时。请参阅@Malek的答案

除此之外,您还应使用无符号整数,即对所有变量使用 uint32_t

但是,这将提高性能。

如果在上述修复后仍有性能问题,您可以尝试这样做:

  uint32_t N; cin&gt;&gt; N; if(N%2 == 0){cout&lt;&lt; -1; 返回0; } //替代算法uint32_t R,c; R = 1; c = 1; 而(R!= N){R = 2 * R + 1; if(R> N)R = R-N; ++℃; } cout&lt;&lt; C;   

在我的笔记本电脑上,当测试1..100000范围内的所有奇数时,此算法的速度要快2.5倍。但是,对于1..2 * 10 ^ 9范围内的所有数字可能还不够。

还要注意使用 uint32_t 来避免整数溢出。

12
votes
answers
46 views
+10

不清楚C中的铸造[暂停]

我很惊讶为什么会得到不同的结果。

  uint16_t wCaptureTime = 35; wDeltaTime1 =(uint16_t) - (int16_t)wCaptureTime; wDeltaTime2 = 0xFFFF  - (int16_t)wCaptureTime; printf(“wDeltaTime1%d”,wDeltaTime1); printf(“wDeltaTime2%d”,wDeltaTime2);   

代码导致:

  wDeltaTime1 65501 wDeltaTime2 65500   

有人可以解释或提供一些阅读链接关于那种行为。

沙发
+60

表达式(uint16_t) - (int16_t)wCaptureTime 中的(uint16_t) cast -35 转换为 uint16_t 时,您将获得 -35 + 65536 ,即 65501 < p>如果 sizeof(int)为2,那么 0xFFFF - (int16_t)wCaptureTime 65535 - 35 unsigned 算术是 65500 如果 sizeof(int)为4,那么你将得到相同的结果,尽管表达式将用signed( int )算术计算。

板凳
+30

假设实现使用32位 int wDeltaTime1 int ,那么 DeltaTime1 =中的操作( uint16_t) - (int16_t)wCaptureTime; 是:

  • (int16_t)强制转换 uint16_t wCaptureTime int16_t 值保持为35。
  • int16_t 会自动提升为 int 该值保持为35。
  • 一元 - 运算符取消该值,生成-35。
  • (uint16_t)强制转换将其转换为 uint16_t 转换为< 代码> uint16_t 以模数65536执行,因此结果为-35 + 65536 = 65501。
  • uint16_t 转换为 wDeltaTime1的类型 int 值为65501。
  • 此值分配给 wDeltaTime1 ,在 wDeltaTime1 中生成65501。

    中的操作wDeltaTime2 = 0xFFFF - (int16_t)wCaptureTime; 是:

    • 0xFFFF 是一个 int 常量值65535。
    • (int16_t)强制转换将 uint16_t wCaptureTime 转换为 int16_t 值保持为35。
    • int16_t 会自动提升为 int 该值保持为35。
    • 二进制 - 运算符从65535中减去35,产生65535 - 35 = 65500。
    • 此值分配给 wDeltaTime2 ,在 wDeltaTime2 中生成65500。

      您可能遇到的一个混淆源是 uint16_t 中的否定是等效的减去65536,而不是65535(或 0xFFFF )。65535是16位的“全1”模式; 它不像零一样。65536是 uint16_t 包裹的地方,所以它的行为更像零。

      按位补码运算符,<

@Lundin:谢谢,实际上有几个地方没有自动促销。我更新了答案。 - 昨天Eric Postpischil

地板
+20

在第一种情况下,您将-35转换为 uint16_t 这是65501:

   - (uint16_t)35 = 65501(作为uint16_t)  

在第二种情况下,第一个操作数是0xffff(65535)所以你得到65535 - 35 = 65550:

  65535  - (uint16_t)35 = 65500  
     
			
        

不,C中没有隐含的操作数。 - John Bollinger昨天

@JohnBollinger:我认为他的意思是-x隐式为0-x,而不是我同意该演示文稿。 - 昨天Eric Postpischil

@EricPostpischil,只有当运算符被解释为二进制时,才有一个隐含的第一个操作数 - 当然它是一元的 - 。结果在代数上相当于从0减去单个操作数是一个弱的支柱,部分原因是代数等价总是赋予计算等价,部分原因是两个算子具有不同的优先级。 - 昨天John Bollinger

@JohnBollinger:我不是在谈论C运营商。数学上,-x是0-x。 - 昨天Eric Postpischil

这个答案有误导性。在第二种情况下,第一个操作数是0xFFFF,它将适合int或无符号int。它始终是一个正值,并且永远不会在任何系统上被视为-1,除非明确地转换为有符号类型。 - 昨天伦丁

4楼
+10

第1行:

  • (int16_t)wCaptureTime; 触发显式转换为 int16_t 保留值 35
  • - (int16_t)wCaptureTime; 应用一元 - 运算符。对于32位或更大的计算机, wCaptureTime 是整数提升为 int 对于8/16位计算机,类型仍为 int16_t
  • (uint16_t) - (int16_t)wCaptureTime; 触发显式将负值转换为 uint16_t 此转换按照C17 6.3.1.3进行:

    否则,unsigned int 也是(无论演员如何) - 因为“通常的算术转换”。在这种情况下,与第1行中的无符号转换相同,您最终会得到类似无符号算术 65535 - 0xFFDD = 34十进制的内容。

  • 如果 0xFFFF int ,然后操作数(int16_t)wCaptureTime; 将被提升为 int 该操作只需使用两个 int 操作数执行, 65535 - 35 = 65500

    Study 两个补码

-35到uint16_t的转换由C标准(6.3.1.3 2,modulo)定义,而不是实现定义的。 - 昨天Eric Postpischil

你迟到了,但我认为这是一个特别好的答案。 - 昨天的芭丝谢芭

@EricPostpischil是的,它是实现定义的格式(2的compl) - 昨天的Lundin

10
votes
answers
108 views
+10

如果为空则不要添加到列表c#[保留]

我正在尝试从匿名函数创建一个列表。如果请求模型属性不为null,我希望创建列表。目前,它正在向列表添加null

代码

  public void方法(RequestModel请求){var create = new DtoModel {docs = new List&lt; docsModel&gt; {request.FirstDoc!= null?runFunction(request.FirstDoc):null,request.SecondDoc!= null?runFunction(request.SecondDoc):null,request.ThirdDoc!= null?runFunction(request.ThirdDoc):null,}}; }   

目前,即使任何文档为null,它也会创建一个计数列表3。我将列出仅在docs不为null且列表应仅包含非null的文档时才创建。不应该有任何空值。请求模型可以包含x个文档。

我知道我之后可以使用Linq删除空值,但我正在寻找一个解决方案,它不会在列表中创建空元素。

沙发
+100

基本上你不能用集合初始化器 - 集合初始化器总是添加与逗号分隔列表中的条目相同数量的元素。(我想你可以有一个 Add 方法忽略空值的集合,但 Add 肯定会被调用相同的次数。)

,只需使用 if 语句:

  if(request.FirstDoc!= null){create.docs.Add(runFunction(request.FirstDoc)); } // etc   

您总是可以使用本地方法来简化:

  public void method(RequestModel request){var create = new DtoModel { docs = new List&lt; docsModel&gt;()}; MaybeAdd(request.FirstDoc); MaybeAdd(request.SecondDoc); MaybeAdd(request.ThirdDoc); void MaybeAdd(docsModel doc){if(doc!= null){create.docs.Add(runFunction(doc)); }}   

如果一切都为null,我最初错过了关于列表本身未被初始化的部分。为此,您需要更改它以在每次添加时检查初始化:

  public void method(RequestModel request){var create = new DtoModel() ; MaybeAdd(request.FirstDoc); MaybeAdd(request.SecondDoc); MaybeAdd(request.ThirdDoc); void MaybeAdd(docsModel doc){if(doc!= null){if(create。)docs == null){create.docs = new List&lt; docsModel&gt;(); } create.docs.Add(runFunction(doc));   

顺便说一句,我强烈建议您开始遵循正常的.NET命名约定,使用PascalCase来处理类型和属性( DocsModel Method RunFunction Docs )。

另外,我想(谦卑地)向OP推荐他/她检查三元运算符的工作原理docs.microsoft.com/en-us/dotnet/csharp/language-reference/ - burkay 8月30日22:46

@burkay:我没有看到他们不知道条件运算符的作用。我不认为这是令他们困惑的部分。 - Jon Skeet 8月31日5:50

板凳
-10

使用Linq

您可以使用一点LINQ完成您想要的任务。

  var create = new DtoModel {docs =(new [] {request.FirstDoc,request.SecondDoc,request.ThirdDoc})。Where(d =&gt; d!= null)。选择(d =&gt; runFunction(d))。ToList()};   

更长但更容易阅读

这有点难以阅读,所以我建议将其分解一下。

创建一个辅助方法将请求展开到数组中:

  static public T [] CreateArray&lt; T&gt;(params T [] input){return input; }   

然后以这种方式编写:

  var requests = CreateArray(request.FirstDoc,request.SecondDoc,request.ThirdDoc); var processedRequests = requests.Where(r =&gt; r!= null).Select(r =&gt; runFunction(r)); var create = new DtoModel {docs = processedRequests.ToList()};   

或者如果你喜欢使用三元运算符,就像在你的例子中一样,你可以这样做:

  public void method(RequestModel request){ var create = new DtoModel {docs = CreateArray(request.FirstDoc!= null?runFunction(request.FirstDoc):null,request.SecondDoc!= null?runFunction(request.SecondDoc):null,request.ThirdDoc!= null?runFunction (request.ThirdDoc):null,}。Where(d =&gt; d!= null).ToList()};
     
			
        

OP表示不使用linq。我同意他的看法。要构造一个包含空值的列表,然后构造另一个带有空值的过滤器,那么从一开始就以正确的方式构造它就没有意义了。 - 丹尼尔施密德8月31日7:28

仔细读。我相信他不想使用linq“之后删除空值”,即希望魔法在集合初始化器中发生。我认为我的代码确实如此。 - John Wu 8月31日7:30

在上一个示例中,您创建一个数组,然后过滤空值(Where(...)),然后从中创建一个List。这就是代码的作用 - Daniel Schmid 8月31日7:39

什么清单?我没有看到任何清单。我看到一个IEnumerable。列表创建一次,使用ToList(),具有正确数量的元素......全部在集合初始值设定项中。 - John Wu 8月31日7:40

7
votes
answers
46 views
+10

在悬停时翻转半圆

我想在悬停时翻转半圆。

  .main {border:2px solid green; border-radius:190px; 身高:200px; 宽度:200px; } .btm {border-bottom-left-radius:190px; border-bottom-right-radius:190px; 背景颜色:红色; 身高:100px; }   
 &lt; div class =“main”&gt; &lt; div style =“height:100px;”&gt; &LT; / DIV&GT; &lt; div class =“btm” &GT; &LT; / DIV&GT; &LT; / DIV&GT;     

上面的代码圆圈的底部是红色的,我想要的只是我想让圆圈的顶部成为悬停时红色

任何帮助都会得到赞赏。

沙发
+30
+50

您可以使用线性渐变(180度,透明50%,红色50%); 轻松实现此目的。你可以在主要部门悬停时交换颜色。希望这是你要找的。

  .main {border:2px solid green; border-radius:190px; 身高:200px; 宽度:200px; 背景:线性梯度(180度,透明度50%,红色50%); } .main:hover {background:linear-gradient(180deg,red 50%,transparent 50%); }   
 
			
        
+30

  .main {border:2px solid green; border-radius:190px; 身高:200px; 宽度:200px; 过渡:全部0.5秒轻松; } .btm {border-bottom-left-radius:190px; border-bottom-right-radius:190px; 背景颜色:红色; 身高:100px; 过渡:全部0.5秒轻松; } .div-1 {border-top-left-radius:190px; 过渡:全部0.5秒轻松; border-top-right-radius:190px; } .main:hover .div-1 {background:red; 过渡:全部0.5秒轻松; } .main:hover .btm {background:white; 过渡:全部0.5秒轻松; }   < pre class =“snippet-code-html lang-html prettyprint-override”> &lt;!DOCTYPE html&gt; &LT; HTML&GT; &LT; HEAD&GT; &lt; meta charset =“utf-8”&gt; &lt; meta name =“viewport”content =“width = device-width”&gt; &lt; title&gt; JS Bin&lt; / title&gt; &LT; /头&GT; &LT;身体GT; &lt; div class =“main”&gt; &lt; div style =“height:100px;” 类= “DIV-1” &GT; &LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &LT; / DIV&GT; &LT; /体&GT; &lt; / html&gt;     

我添加了过渡效果并使用了您的代码!希望它能帮助 DOCTYPE html&gt; &LT; HTML&GT; &LT; HEAD&GT; &lt; meta charset =“utf-8”&gt; &lt; meta name =“viewport”content =“width = device-width”&gt; &lt; title&gt; JS Bin&lt; / title&gt; &LT; /头&GT; &LT;身体GT; &lt; div class =“main”&gt; &lt; div style =“height:100px;” 类= “DIV-1” &GT; &LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &LT; / DIV&GT; &LT; /体&GT; &lt; / html&gt;

我添加了过渡效果并使用了您的代码!希望它能帮助 DOCTYPE html&gt; &LT; HTML&GT; &LT; HEAD&GT; &lt; meta charset =“utf-8”&gt; &lt; meta name =“viewport”content =“width = device-width”&gt; &lt; title&gt; JS Bin&lt; / title&gt; &LT; /头&GT; &LT;身体GT; &lt; div class =“main”&gt; &lt; div style =“height:100px;” 类= “DIV-1” &GT; &LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &LT; / DIV&GT; &LT; /体&GT; &lt; / html&gt;

我添加了过渡效果并使用了您的代码!希望它能帮助 LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &LT; / DIV&GT; &LT; /体&GT; &lt; / html&gt;

我添加了过渡效果并使用了您的代码!希望它能帮助 LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &LT; / DIV&GT; &LT; /体&GT; &lt; / html&gt;

我添加了过渡效果并使用了您的代码!希望它能帮助

+10

试试这个。

  .main {position:relative; 身高:200px; 宽度:200px; 边框:2px实心绿色; border-radius:190px; } .semi-circle {position:absolute; 位置:绝对; border-bottom-left-radius:200px; border-bottom-right-radius:200px; 背景颜色:红色; 身高:100px; 宽度:200px; 最高:50%; } .main:hover .semi-circle {transform:rotate(180deg); 最高:0%; }   
 &lt; div class =“main”&gt; &lt; div class =“semi-circle”&gt; &LT; / DIV&GT; &lt; / div&gt;    

     
			
        
0

你所要做的就是将你的div翻译到顶部,同时将它旋转到180度。

同样有一个CSS属性 transform:translate(tx) ,ty)旋转(度);

这里 tx 代表像素,你要翻译 x-axis ,< code> ty 代表像素,你要在 y轴上翻译, degrees 代表你想要旋转对象的度数。

你的代码是一样的。我刚刚添加了一个CSS类来使它工作。看看。

  .main {border:2px solid green; border-radius:190px; 身高:200px; 宽度:200px; } .btm {border-bottom-left-radius:190px; border-bottom-right-radius:190px; 背景颜色:红色; 身高:100px; } .main:hover .btm {transform:translate(0,-100px)rotate(180deg); }   
 &lt; div class =“main”&gt; &lt; div style =“height:100px;”&gt; &LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &lt; / div&gt;     

谢谢。

  .main {border:2px solid green; border-radius:190px; 身高:200px; 宽度:200px; } .btm {border-bottom-left-radius:190px; border-bottom-right-radius:190px; 背景颜色:红色; 身高:100px; } .main:hover .btm {transform:translate(0,-100px)rotate(180deg); }   
 &lt; div class =“main”&gt; &lt; div style =“height:100px;”&gt; &LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &lt; / div&gt;     

谢谢。 border-radius:190px; 身高:200px; 宽度:200px; } .btm {border-bottom-left-radius:190px; border-bottom-right-radius:190px; 背景颜色:红色; 身高:100px; } .main:hover .btm {transform:translate(0,-100px)rotate(180deg); }

 &lt; div class =“main”&gt; &lt; div style =“height:100px;”&gt; &LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &lt; / div&gt;     

谢谢。 border-radius:190px; 身高:200px; 宽度:200px; } .btm {border-bottom-left-radius:190px; border-bottom-right-radius:190px; 背景颜色:红色; 身高:100px; } .main:hover .btm {transform:translate(0,-100px)rotate(180deg); }

 &lt; div class =“main”&gt; &lt; div style =“height:100px;”&gt; &LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &lt; / div&gt;     

谢谢。 btm {transform:translate(0,-100px)rotate(180deg); }

 &lt; div class =“main”&gt; &lt; div style =“height:100px;”&gt; &LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &lt; / div&gt;     

谢谢。 btm {transform:translate(0,-100px)rotate(180deg); }

 &lt; div class =“main”&gt; &lt; div style =“height:100px;”&gt; &LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &lt; / div&gt;     

谢谢。

0

这是一个依赖于 background-clip

  .main {边框:2px实心绿色; border-radius:50%; 身高:200px; 宽度:200px; 箱尺寸:边界盒; 背景色:红色; 背景剪辑:内容盒; 填充:100px 0 0; } .main:hover {padding:0 0 100px; }   
 &lt; div class =“main”&gt; &lt; / div&gt;     < p>您可以轻松转换的位置: 

  .main {border:2px solid green ; border-radius:50%; 身高:200px; 宽度:200px; 箱尺寸:边界盒; 背景色:红色; 背景剪辑:内容盒; 填充:100px 0 0; 过渡:1秒; } .main:hover {padding:0 0 100px; }   
 &lt; div class =“main”&gt; &lt; / div&gt;     

如果你想要一个翻译动画,这里有一个渐变的想法:

  .main {border :2px纯绿色; border-radius:50%; 身高:200px; 宽度:200px; 背景:线性渐变(红色,红色)底部; 背景大小:100%50%; 背景重复:不重复; 过渡:1秒; } .main:hover {background-position:top; }   
 &lt; div class =“main”&gt; &LT; / DIV&GT;  

     
			
        
0

你可以看到这个例子:

  .main {border:2px solid green; border-radius:190px; 身高:200px; 宽度:200px; 位置:相对; 溢出:隐藏; } .btm {border-bottom-left-radius:190px; border-bottom-right-radius:190px; 背景颜色:红色; 身高:100px; 位置:绝对的; 最高:50%; 左:0; 宽度:100%; 过渡:.3s; } .main:hover .btm {top:0; border-top-left-radius:190px; border-top-right-radius:190px; border-bottom-left-radius:0; border-bottom-right-radius:0; }   
 &lt; div class =“main”&gt; &lt; div style =“height:100px;”&gt; &LT; / DIV&GT; &lt; div class =“btm”&gt; &LT; / DIV&GT; &lt; / div&gt;    

     
			
        

最初我希望在悬停时底部看起来是红色的我想让顶部变红。 - 昨天的Deepshika S.

在你的答案中,最初的底部不是红色 - 昨天的Deepshika S.

请检查我的更新代码。:) - TanBir开发人员23小时前

13
votes
answers
34 views
+10

从lambda返回变体

我有这个简单的lambda:

  std :: variant&lt; int,char&gt; myLambda = [](){//没有合适的用户定义的从“type”到“std :: variant&lt; int,char&gt;”的转换 存在std :: variant&lt; int,char&gt; 水库; if(true){res = 1; } else {res ='c'; } return res; };   

但是它没有编译,产生错误没有合适的用户定义的转换,从“type”到“std :: variant&lt; int,char&gt;” 存在我做错了什么?

沙发
+60
+50

lambda表达式类型错误。您正在尝试绑定到 std :: variant&lt; int,char&gt; Lambda表达式类型是 ClosureType 使用 auto

  auto processProjectFile = [](){std :: variant&lt; int,char&gt; 水库; if(true){res = 1; } else {res ='c'; } return res; };   

或者,你可以将 ClosureType 强制转换为 std :: function ,用 std替换 auto :: function&lt; std :: variant&lt; int,char&gt;(void)&gt;

但是如果你打算调用lambda,只需替换}; 最后由

是的,这是我错过的。谢谢。我遇到过的愚蠢错误。BTW std :: function部分很方便!谢谢! - Nurbol Alpysbayev 8月30日12:32

不确定ClosureType是什么意思。一个lambda类型的名称是impl-defined - Lightness Races in Orbit 8月30日13:27

+70

要么是指

  std :: variant&lt; int,char&gt; v = [](){std :: variant&lt; int,char&gt; 水库; if(true){res = 1; } else {res ='c'; } return res; }(); ^^^   

或者你的意思是

  auto myLambda = [](){std :: variant&lt; int,char&gt; 水库; if(true){res = 1; } else {res ='c'; } return res; };   

Lambda表达式具有唯一类型。